Deta – micro server miễn phí dành cho dev

Mở đầu Đôi khi chúng ta cần một web server đơn giản, public ra internet để thực thi vài tác vụ linh tinh, hoặc để hosting một số file khi cần. Tuy nhiên, với tư cách là một dev/pentester “nhà nghèo” thì việc có thẻ visa để đăng ký free cloud của Google, AWS, Oracle

Mở đầu

Đôi khi chúng ta cần một web server đơn giản, public ra internet để thực thi vài tác vụ linh tinh, hoặc để hosting một số file khi cần. Tuy nhiên, với tư cách là một dev/pentester “nhà nghèo” thì việc có thẻ visa để đăng ký free cloud của Google, AWS, Oracle thôi nhiều khi đã là cả một vấn đề lớn 🤣. Đùa chút thôi, bài viết này mình sẽ giới thiệu Deta – một công cụ cho phép bạn nhanh chóng tạo micro-website/API và public ra internet. Here we go~

Deta

image.png

https://deta.sh là công cụ Cloud cá nhân miễn phí cho phép chúng ta xây dựng các ứng dụng, prototype rồi public ra internet một cách nhanh chóng.

Deta đi kèm với:

  • Deta Base: NoSQL database (giống như MongoDB)
  • Deta Micros: Cho phép bạn deploy ứng dụng của mình lên internet (giống như Heroku). Deta cho tạo thoải mái bao nhiêu micros cũng được hết 😳
  • Deta Drive: Cho phép lưu trữ file (giống như Google Drive và AWS S3)

Deta hiện đang hỗ trợ các ngôn ngữ: Python, Node.js, và Golang. Với mỗi ngôn ngữ, Deta cũng hỗ trợ các micro-framework ví dụ như Python là FastAPI hoặc Flask.

Để lấy ví dụ, mình sẽ xây dựng ứng dụng đơn giản dành cho pentester như sau:

  1. Cho phép tải file lên theo URL và MIME Type tùy ý. VD: truy cập vào link: “https://myfakeserver.com/aaa.png” nhưng trả ra content là alert(origin) và mime type lại là javascript (chứ không phải file ảnh như đuôi PNG).
  2. Cho người dùng điền trực tiếp nội dung file.
  3. Cho phép xoá file.

Cài đặt

Tất cả hướng dẫn sử dụng (đầy đủ và chi tiết) đều có ở https://docs.deta.sh/docs/home

Trước hết là chúng ta cần đăng ký tài khoản. Màn hình quản lý nằm ở: https://web.deta.sh/home

Sau đó, ta tải về Deta CLI rồi đăng nhập:

curl -fsSL https://get.deta.dev/cli.sh |sh
deta login

sau đó tạo một micro mới với framework là python:

deta new payload-server --python

Successfully created a new micro
{"name":"payload-server",
	"id":"xxxxxx",
	"project":"xxxxxxx",
	"runtime":"python3.9",
	"endpoint":"https://xxxxxxx.deta.dev",
	"region":"ap-southeast-1",
	"visor":"disabled",
	"http_auth":"disabled"}

xem thử file vừa tạo:

➜  payload-server cat main.py
def app(event):
    return"Hello, world!"%

Ngay ở bước này chúng ta có thể chạy deta deploy và app của chúng ta sẽ được deploy lên URL ở trên. Quá nhanh, quá nguy hiểm:

image.png

Chúng ta cũng có thể cài đặt thêm các thư viện, tạo file requirements.txt và điền tên các thư viện vào, ở đây ta sẽ cần đến Flask và Deta

flask
deta

Mỗi lần sửa code xong xuôi thì nhớ deta deploy để đẩy code lên nhé

Backend

Sửa lại file main.py như sau, vì code cũng khá ngắn có 88 dòng và đơn giản nên mình sẽ không đi vào từng bước mà chỉ giải thích một số vị trí quan trọng.

from flask import Flask
from flask import Flask, request, render_template, abort, Response, flash, redirect
from deta import Deta
import uuid

app = Flask(__name__)

app.secret_key =b'somethingrandom'

deta = Deta("PROJECT_KEY_HERE")
drive = deta.Drive("files")
db = deta.Base("payload_db")@app.route("/", defaults={"path":""}, methods=["GET","POST"])@app.route("/<path:path>")defcatch_all(path):if path =="":if request.method =='POST':return upload()else:
            res = db.fetch()
            all_items = res.items

            return render_template("index.html", items=all_items)elif path =="delete":return delete()else:return download(path)defupload():file= request.files.get("file")
    submitted_mime = request.form.get("mime")
    submitted_path = request.form.get("path")
    content = request.form.get("content")
    mime ="text/plain"if submitted_mime:
        mime = submitted_mime

    iffile:
        mime =file.content_type
        content =fileelifnot content:
        flash("[ERROR] No content!")return redirect("/")ifnot submitted_path:
        flash("[ERROR] No path!")return redirect("/")if db.fetch({"path": submitted_path}, limit=1).items:
        flash("[ERROR] Duplicate path!")return redirect("/")

    filename =str(uuid.uuid4())
    db.put({"path": submitted_path,"filename": filename,"mime": mime})
    res = drive.put(filename, content, content_type=mime)if res:
        flash(f"[OK] file uploaded to path: {submitted_path}")return redirect("/")defdownload(path):
    items = db.fetch({"path": path}, limit=1).items
    if items:file= drive.get(items[0]['filename'])
        content =file.read()file.close()return Response(content, mimetype=items[0]['mime'])else:return abort(404)defdelete():
    path = request.args.get("p")
    items = db.fetch({"path": path}, limit=1).items
    if items:
        db.delete(items[0]['key'])
        drive.delete(items[0]['filename'])

        flash(f"[OK] path '{path}' deleted!")return redirect("/")else:return abort(404)# Uncomment this line to debug local# app.run()

Ở đoạn này chúng ta cần tạo Project Keys (tương tự API key) trong giao diện ở dưới, drivedb là các object giúp chúng ta tương tác với database và drive:

image.png

deta = Deta("PROJECT_KEY_HERE")
drive = deta.Drive("files")
db = deta.Base("payload_db")

Phần route, chúng ta sẽ tạo một route dùng để catch all (bắt tất cả các request) rồi kiểm tra:

  • Nếu là path index => chuyển đến trang upload.
  • Nếu là path delete => chuyển đến trang xoá file
  • Còn lại thì mặc định là xử lý trả về nội dung file (nếu có tồn tại)

Deta đã cũng cấp sẵn cho chúng ta các phương thức để tương tác với DB:

db.put({"path": submitted_path,"filename": filename,"mime": mime})

Dùng để insert một bản ghi vào DB. Chúng ta sẽ lưu lại path (để kiểm tra xem có bị trùng không), filename thì sinh ngẫu nhiên bằng uuid, mime do người dùng tự nhập hoặc lấy ra từ file tải lên. Dữ liệu trong DB sẽ có dạng sau:

{'filename': 'ee8945e3-b7aa-4d0a-829a-b472aecb1ef2', 'key': '2zd58xhd6hvi', 'path': 'abc.png'}
db.fetch({"path": submitted_path}, limit=1)

dùng để lấy ra dữ liệu, có thể query chính xác hoặc theo syntax gần với MongoDB: https://docs.deta.sh/docs/base/queries.

db.delete(items[0]['key'])

Dùng để xóa file dựa theo key. Ta cũng có thể tương tác trực tiếp thông qua giao diện ở https://web.deta.sh/home:

image.png

Rất đơn giản đúng không nào? Tương tác với Drive cũng hoàn toàn tương tự:

# Upload file
drive.put(filename, content, content_type=mime)# Đọc nội dung filefile= drive.get(items[0]['filename'])
content =file.read()file.close()# Xóa file theo filename 
drive.delete(items[0]['filename'])

Drive cũng có giao diện trực quan:

image.png

Frontend

Không màu mè, hoa lá, giao diện thuần HTML, no CSS 🤣

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Payload Server</title></head><body><h1>Payload Server</h1>

    {% with messages = get_flashed_messages() %}
    {% if messages %}
    <ul>
    {% for message in messages %}
        <li>{{ message }}</li>
    {% endfor %}
    </ul>
    {% endif %}
    {% endwith %}

    <h2>Upload</h2><formaction="/"enctype="multipart/form-data"method="post"><inputname="file"type="file"><br><br><labelfor="path">URL Path</label><inputname="path"type="text"><br><br><labelfor="mime">MIME (default to <code>text/plain</code> or file's mime)</label><inputname="mime"type="text"><br><br><labelfor="path">Content (if no file is selected)</label><textareaname="content"id="content"cols="50"rows="5"></textarea><br><br><inputtype="submit"></form><h2>List payloads</h2>
    {% if items %}
    <ul>
        {% for item in items %}
        {% set p = item['path']%}
        <li><ahref="/{{p}}">/{{p}}</a> - <ahref="/delete?p={{p}}">Delete</a></li>
        {% endfor %}
    </ul>
    {% endif %}
</body></html>

It’s Demo Time

Chạy deta deloy và xem thành quả thôi: https://8r8cjf.deta.dev/

Giới hạn

Tất nhiên là với dịch vụ Free như thế này thì sẽ đi kèm với một số giới hạn chính sau:

  • Các micros thực tế là chạy trên Lambda nên thời gian khởi động (sau khi sleep) sẽ có thể bị chậm.
  • RAM chỉ có 512MB.
  • Các request sẽ time-out sau 10 giây, nên không thể chạy các process trong thời gian dài.
  • Nếu không upload lên Drive thì chỉ có thể upload lên thư mục /tmp/.
  • Drive có dung lượng 10GB.
  • Thư viện tối đa 250 MB, source code tối đa 250MB.

Chi tiết hơn ở: https://docs.deta.sh/docs/micros/about

Nhưng với mục đích để prototype và demo thì thế này vẫn quá là OK la 😊

Ngoài ra còn gì?

Deta còn cung cấp một số tiện ích khá hữu ích:

  • Deta Crons cho phép chạy các task theo định kỳ (như cronjob trong Linux).
  • Deta Visor cho phép chúng ta xem log request/response đến micro và log lỗi.
  • Cho phép custom subdomain (VD: https://myserver.deta.dev/) và domain riêng, quá tiện lợi cho các anh em dev làm web mời cưới 😅

image.png

Kết

Chúc mọi người tận dụng Deta hiệu quả và có nhiều ý tưởng hay ho nhá 😀

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ