標籤: cloudflare

  • 實作 js 函式庫包裝為 API 提供給後端呼叫

    實作 js 函式庫包裝為 API 提供給後端呼叫

    最近在想有滿多 js 實作資料處理的函式庫,於是想看有沒有 nodejs 或是相似的程式語言可以相容 js 實做包裝城後端,於是想到了用 Cloudflare Worker 服務來實作。

    我拿 iztro 這套服務來實作,我認為很適合包裝成 API 呼叫的功能有幾個特色:

    1. 以處理、整理資料為目的的服務。
    2. 不需要相依其他套件( e.g. jQuery)
    3. 產生的結果是一包字串(json, xml 等),或是能轉成 base64 的檔案字串。

    先附上 Github repo 。名字叫做「My Iztro Worker」,有夠隨便,哈。

    這個服務基於 Cloudflare Worker 實作,實作以下功能:

    • API 服務:接受包含生日、出生時間、性別等參數的 HTTP GET 請求,返回相應的紫微斗數資訊。
    • 使用說明頁面:當請求缺少必要參數時,返回一個包含 API 使用說明和測試表單的 HTML 頁面,方便使用者瞭解如何使用該 API。
    • 速率限制:為了防止濫用,對每個客戶端 IP 設置了每分鐘最多 10 次請求的限制。

    實作了一個 usage.js 頁面作為測試 form 表,並且使用 Worker 特有的功能實作呼叫頻率的限制;src/index.js 中可以依照原始套件的說明參考修改。

    部署方式請參考請參考原始碼的 README,我作了一個線上範例,視狀況可能會停用,且用且珍惜:


    同場加映,請 AI 協助生成實作 nodejs 的說明:

    將 JavaScript 函式庫包裝為 API,提供後端呼叫,是現代軟體開發中常見的需求。這種方法能夠將複雜的邏輯封裝起來,透過標準化的介面供其他應用程式或服務使用。以下是實作此項目的簡要流程:

    1. 選擇適當的執行環境: 首先,選擇一個適合執行 JavaScript 的環境。Node.js 是一個常見的選擇,因為它允許在伺服器端執行 JavaScript。此外,像 Cloudflare Workers 這樣的伺服器無關環境也提供了在邊緣節點執行 JavaScript 的能力。
    2. 建立專案結構: 為您的 API 建立一個新的專案目錄,並初始化專案:
       mkdir my-js-api
       cd my-js-api
       npm init -y

    這將建立一個包含預設設定的 package.json 檔案。

    1. 安裝相依套件: 根據您的需求,安裝必要的相依套件。例如,若您需要處理 HTTP 請求,可以安裝 Express.js:
       npm install express
    1. 撰寫 API 邏輯: 在專案目錄中,建立一個主檔案(例如 index.js),並撰寫處理 HTTP 請求的邏輯。以下是一個使用 Express.js 的簡單範例:
       const express = require('express');
       const app = express();
       const port = 3000;
    
       // 引入您的 JavaScript 函式庫
       const myLibrary = require('./myLibrary');
    
       app.use(express.json());
    
       app.post('/api/your-endpoint', (req, res) => {
         const input = req.body.input;
         const result = myLibrary.yourFunction(input);
         res.json({ result });
       });
    
       app.listen(port, () => {
         console.log(`API 伺服器正在 http://localhost:${port} 上運行`);
       });

    在這個範例中,我們建立了一個 POST 端點 /api/your-endpoint,接受 JSON 格式的請求,並使用 myLibrary 中的函式處理輸入。

    1. 測試 API: 在本機運行您的 API 伺服器,並使用工具(如 Postman)或命令列工具(如 curl)進行測試:
       curl -X POST http://localhost:3000/api/your-endpoint -H "Content-Type: application/json" -d '{"input": "your data"}'

    確保您的 API 能夠正確處理請求並返回預期的結果。

    1. 部署 API: 根據您的需求,將 API 部署到適當的環境中。例如,您可以將其部署到雲端服務提供商(如 AWS、Heroku)或使用 Docker 容器進行部署。
    2. 實作速率限制和安全性: 為了防止濫用,建議實作速率限制機制。此外,確保您的 API 僅允許授權的請求,並實作適當的驗證和授權機制。

    透過上述步驟,您可以將 JavaScript 函式庫包裝為 API,供後端系統呼叫,實現功能的模組化和重用性。

  • 如何在網站中整合 Google reCAPTCHA v3

    如何在網站中整合 Google reCAPTCHA v3

    關於 Google reCAPTCHA v3 ,才想起來之前用的幾乎都是 v2 ,應該更新一下自己的技能樹,真的腿。

    幾個注意事項:

    1. 幾個注意的要點:
      • 引用 js 檔案,注意前端使用 site key
      • 後端的 Secret Key 作驗證,注意不要外流
    2. 下面提供操作流程,除了使用 js 驗證的方法之外,官網也由提供 onSubmit 的方法,參考這裡
    3. 後端確認的說明參考官網,這裡。注意分數的判斷。
    4. 如果不想用分數來做判斷,可以選用 v2 ,他也有不同的操作模式,參考這裡這裡
    5. 有其使用限制,不同版本參考這裡,免費上限是 10k / 月,注意是一個帳戶。
    6. 有一些操作細節,像是 action 的設置可以作為不同驗證分數的評估手段等等。

    另外除了 Google reCAPTCHA v3 也有其他替代品,Cloudflare 也提供 Turnstile ,計費方式不太一樣。除了上述兩個,還有 hCaptcha ,甚至他還提供了 reCAPTCHA 轉換 hCAPTCHA 的說明,價格參考這裡(好像免費只能試用?)。

    Google reCAPTCHA v3 驗證邏輯上大概就是 Google 透過魔法(笑)在前端透過瀏覽器判斷這個用戶是不是機器人,產出一個驗證的落落長咒語,然後傳給後端確認,後端透過回傳給 google 來判斷 score,自行判斷是不是機器人,我理解大致上 0.5 以上就是人類。

    關於操作的流程,其實官網文章其實已經說了很明白了。既然要水字數的話,來人阿!上 AI:

    如何在網站中整合 Google reCAPTCHA v3

    Google reCAPTCHA v3 是一個無干擾的防護機制,它不需要使用者解決驗證挑戰,透過評分系統自動識別惡意行為。以下將介紹如何在網站中實作 reCAPTCHA v3 的步驟。

    步驟 1: 註冊 Google reCAPTCHA v3

    1. 進入 Google reCAPTCHA 管理台
    2. 登入你的 Google 帳戶,並填寫下列資訊:
      • 標籤:為這個 reCAPTCHA v3 設定提供一個識別名稱。
      • reCAPTCHA 類型:選擇 “reCAPTCHA v3″。
      • 網域:輸入你網站的網域名稱。
      • 所有者:設定擁有這個 reCAPTCHA 的電子郵件。
    3. 同意 reCAPTCHA 服務條款,並點擊 “提交”。

    完成註冊後,你將獲得 站點金鑰 (Site Key)祕密金鑰 (Secret Key)

    步驟 2: 將 reCAPTCHA v3 加入你的網站

    在你的 HTML 頁面中,加入下列 JavaScript 程式碼以載入 reCAPTCHA v3:

    <script src="https://www.google.com/recaptcha/api.js?render=你的站點金鑰"></script>

    在你想要執行驗證的操作中(例如表單提交),調用 grecaptcha.execute()

    <script>
      grecaptcha.ready(function() {
        grecaptcha.execute('你的站點金鑰', {action: 'submit'}).then(function(token) {
          // 將 token 傳送至你的伺服器進行驗證
        });
      });
    </script>

    步驟 3: 在後端進行驗證

    當使用者提交表單時,你需要在伺服器端驗證 reCAPTCHA token。以下範例為使用 PHP 進行驗證:

    <?php
      $token = $_POST['token'];
      $secret_key = '你的祕密金鑰';
    
      $response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret_key}&response={$token}");
      $responseKeys = json_decode($response, true);
    
      if ($responseKeys["success"] && $responseKeys["score"] >= 0.5) {
        // 驗證通過,繼續處理表單
      } else {
        // 驗證失敗,阻止表單提交
      }
    ?>

    步驟 4: 調整評分閾值

    Google reCAPTCHA v3 使用 0 到 1 的評分來衡量使用者行為,1 表示良好使用者,0 表示惡意行為。你可以根據需求來調整評分閾值,例如將其設為 0.5 以上代表驗證通過。

    以上,再來補一個 Cloudflare Turnstile 操作流程。

    Cloudflare Turnstile 操作流程

    1. 註冊並取得 Turnstile 金鑰

    • 首先,登入你的 Cloudflare 帳戶,進入 Turnstile 管理頁面。
    • 點選「新增站點」,輸入你的網站名稱和網域,選擇所需的小工具模式(例如隱形或管理模式)。
    • 完成後,系統會生成一組 sitekeysecret key,請妥善保存這些金鑰,因為它們將用於驗證操作。

    2. 在網站前端加入 Turnstile

    在你的 HTML 頁面 <head> 區塊中插入以下 JavaScript 程式碼,用以載入 Turnstile 小工具:

    <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

    接著,在需要驗證的位置,加入以下 HTML 元素,例如表單內:

    <form id="login-form" action="/login" method="POST">
        <input type="text" name="username" placeholder="用戶名" required>
        <input type="password" name="password" placeholder="密碼" required>
        <div class="cf-turnstile" data-sitekey="YOUR-SITE-KEY"></div>
        <button type="submit">登入</button>
    </form>

    這段代碼會在頁面上自動載入 Turnstile 小工具,用於保護表單提交。

    3. 後端驗證 Turnstile Token

    當使用者提交表單後,Turnstile 會返回一個 token,必須在伺服器端進行驗證。

    以下是後端驗證 token 的範例:

    <?php
      // 從表單中接收 Turnstile 的 response token
      $turnstileToken = $_POST['cf-turnstile-response'];
      
      // 你的 secret key,請妥善保管
      $secretKey = 'your-secret-key';
    
      // 設置驗證請求的參數
      $data = [
        'secret' => $secretKey,
        'response' => $turnstileToken,
        'remoteip' => $_SERVER['REMOTE_ADDR'] // 可選的,用來記錄用戶 IP
      ];
    
      // 初始化 cURL
      $ch = curl_init();
    
      // 配置 cURL 請求
      curl_setopt($ch, CURLOPT_URL, "https://challenges.cloudflare.com/turnstile/v0/siteverify");
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    
      // 執行 cURL 請求並獲取回應
      $response = curl_exec($ch);
      curl_close($ch);
    
      // 將 JSON 格式的回應轉換為 PHP 陣列
      $responseData = json_decode($response, true);
    
      // 檢查驗證結果
      if ($responseData['success']) {
        // 驗證成功,執行你的邏輯
        echo '驗證成功,繼續進行處理';
      } else {
        // 驗證失敗
        echo '驗證失敗,請重試';
      }
    ?>

    你也可以用 Cloudflare Worker 處理:

    // This is the demo secret key. In production, we recommend
    // you store your secret key(s) safely.
    const SECRET_KEY = "1x0000000000000000000000000000000AA";
    
    async function handlePost(request) {
      const body = await request.formData();
      // Turnstile injects a token in "cf-turnstile-response".
      const token = body.get("cf-turnstile-response");
      const ip = request.headers.get("CF-Connecting-IP");
    
      // Validate the token by calling the
      // "/siteverify" API endpoint.
      let formData = new FormData();
      formData.append("secret", SECRET_KEY);
      formData.append("response", token);
      formData.append("remoteip", ip);
    
      const url = "https://challenges.cloudflare.com/turnstile/v0/siteverify";
      const result = await fetch(url, {
        body: formData,
        method: "POST",
      });
    
      const outcome = await result.json();
      if (outcome.success) {
        // ...
      }
    }

    此步驟確保 token 是有效的,且未被重複使用,防止重放攻擊。

    4. 從 Google reCAPTCHA 遷移

    如果你目前使用的是 Google reCAPTCHA,可以使用 Turnstile 的兼容模式,修改載入腳本:

    <script src="https://challenges.cloudflare.com/turnstile/v0/api.js?compat=recaptcha" async defer></script>

    將現有代碼中的 grecaptcha.render() 呼叫,改為使用你的 Turnstile sitekey,這樣可以無縫切換。

    透過這些步驟,你可以在網站中輕鬆整合 Cloudflare Turnstile,提升網站安全性並替代傳統的驗證碼工具。

    同場加映:

    hCaptcha 運作的循序圖,這類操作大多都類似。

    Cloudflare 提供 Turnstile 的計費方式(此為 2024-10-22 時截圖)。這種服務大多就是搶市佔率,然後套養殺的商業模型。到時看看有沒有越來越貴就知道他用的人多不多了。

  • 使用 Cloudflare Workers 處理前端跨域問題

    使用 Cloudflare Workers 處理前端跨域問題

    在 Web Application 走前後端分離的開發時,常會遇到 CORS 的問題,先科普什麼是 CORS,請參考:

    除了使用 JSONP 的處理方式以外,較快的解決方法有:

    1. 前端架設一個 proxy server 提供給前端呼叫使用
    2. 後端 server 端透過 nginx 或其他方法允許跨域的 request

    兩個方法都存在著,正式環境和測試環境在環境設定上必然有所不同,就差在前端改還是後端改了。

    而架設 proxy server 的方法也有兩個常見的作法:

    1. 本地環境架設一個 porxy server ,這邊提供一個 vue+ vite 的範例,請參考
    2. 架設一個在網路上的 proxy server

    原則上來說第一種方式比較保險的,但可能有種種技術因素導致無法實現,於是第二種方法,我們透過 Cloudfalre 來實現了。

    原始碼和別人寫的說明附在最下方,直接講注意事項:

    1. 你需要一個 Cloudflare 帳號,並且有存取 Workers and Pages 這個服務的權限。
    2. 使用 Worker 服務實作,他是公開的,且免費版有 100k 的次數限制,記得要設定白名單避免被濫用
    3. 要記得前端呼叫的網域要透過環境區分,把這個放上正式環境,呼叫次數可能會爆掉。

    更新一些要注意的事項:

    1. 白名單是 request header 中的 Origin ,是來源網址不是 proxy 導向的網址。這如果是後端架設的話得和前端溝通是哪個網址來源。
    2. 針對 Worker 裡面的 fix() 方法我做了一些修改,如果有錯誤還請提醒,程式碼如下:
    function fix(myHeaders) {
      // myHeaders.set("Access-Control-Allow-Origin", "*");
      myHeaders.set("Access-Control-Allow-Headers", event.request.headers.get("access-control-request-headers"));
      myHeaders.set("Access-Control-Allow-Origin", event.request.headers.get("Origin"));
      if (isOPTIONS) {
        myHeaders.set("Access-Control-Allow-Methods", "GET,HEAD,POST,OPTIONS");
    
        //myHeaders.set("Access-Control-Allow-Credentials", "true");
    
        // myHeaders.delete("X-Content-Type-Options");
      }
      return myHeaders;
    }

    我 fork 專案,更新了一個在 header 帶 auth 的版本,應該對防止濫用更有幫助。 網址如下:

    用法在下面兩個連結分享中有說明了,簡單來說就是一個 proxy for api

    這是 cloudflare-cors-anywhere 來源:

    這是關於 cloudflare-cors-anywhere 的操作教學:

    同場加映:

    這裡有修改 response header 的方法,不太推薦,很容易忘記。

  • 使用 Nginx 設定通過 Cloudflare 的真實 IP 與只允許 Cloudflare IP 來的流量。

    使用 Nginx 設定通過 Cloudflare 的真實 IP 與只允許 Cloudflare IP 來的流量。

    一次講兩件事,都是和 Cloudflare 的 IP 有關。

    首先是在Ngnix 中,設定只允許 Cloudflare IP 來的流量。幾點注意:

    1. 需確認 Nginx 設定的網域有沒有通過 Cloudflare 的 Proxy,也就是看 DNS 設定中,橘色的雲有沒有亮起。
    2. 一樣的設定可以套用在其他有 Proxy/VPN/CDN 等操作上。組合拳是:流量走我的,其他檔下來。
    3. 同樣的組合拳也可以設定在單一允許 ip 的 api service 上面,不過請注意邏輯層與系統層的拆分,別被自己的 code 搞死了。
    4. Cloudflare 的 ips 是會更新的,請參考這裡
    5. 如果你有用 crontab 執行 url 的話記得也要把 allow 補進去。例如: allow 127.0.0.1; 或是改成 cli 的操作(推薦)。
    allow 173.245.48.0/20;
    allow 103.21.244.0/22;
    allow 103.22.200.0/22;
    allow 103.31.4.0/22;
    allow 141.101.64.0/18;
    allow 108.162.192.0/18;
    allow 190.93.240.0/20;
    allow 188.114.96.0/20;
    allow 197.234.240.0/22;
    allow 198.41.128.0/17;
    allow 162.158.0.0/15;
    allow 104.16.0.0/13;
    allow 104.24.0.0/14;
    allow 172.64.0.0/13;
    allow 131.0.72.0/22;
    
    allow 2400:cb00::/32;
    allow 2606:4700::/32;
    allow 2803:f800::/32;
    allow 2405:b500::/32;
    allow 2405:8100::/32;
    allow 2a06:98c0::/29;
    allow 2c0f:f248::/32;
    
    deny all; # deny all remaining ips

    再來是設定讓網站在通過 Cloudflare 之後,可以獲取到真實 ip 的設定,這部分我是抄網路的,有些覺得怪的地方,如果有理解錯誤還煩請指正。

    1. set_real_ip_from 是指信任的 proxy ip 所以要設定為 cloudflare 的 ip 段,標示這些來源的 ip 才能正確取得真實的 client ip。
    2. real_ip_header 是修改真實 ip 的 header 字段,默認是 X-Real-IP。改為 CF-Connecting-IP 是 cloudflare 在邊緣到您的來源 Web 伺服器的流量上傳送的標頭。請參考 Cloudflare 文件
    3. 上面提到的流量來源限制和 set_real_ip_from 的設置會衝突,不能一起設置 🫠
    set_real_ip_from 173.245.48.0/20;
    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    set_real_ip_from 103.31.4.0/22;
    set_real_ip_from 141.101.64.0/18;
    set_real_ip_from 108.162.192.0/18;
    set_real_ip_from 190.93.240.0/20;
    set_real_ip_from 188.114.96.0/20;
    set_real_ip_from 197.234.240.0/22;
    set_real_ip_from 198.41.128.0/17;
    set_real_ip_from 162.158.0.0/15;
    set_real_ip_from 104.16.0.0/13;
    set_real_ip_from 104.24.0.0/14;
    set_real_ip_from 172.64.0.0/13;
    set_real_ip_from 131.0.72.0/22;
    
    set_real_ip_from 2400:cb00::/32;
    set_real_ip_from 2606:4700::/32;
    set_real_ip_from 2803:f800::/32;
    set_real_ip_from 2405:b500::/32;
    set_real_ip_from 2405:8100::/32;
    set_real_ip_from 2a06:98c0::/29;
    set_real_ip_from 2c0f:f248::/32;
    
    #use any of the following two
    
    real_ip_header CF-Connecting-IP;
    #real_ip_header X-Forwarded-For; # 滿多人用這個,不過 cf 有自己比較安全的標頭。

    同場加映 Cloudflare 的 ips 清單,更新頻率不高,不過設定上幾個注意:

    1. 相關 ips 的設定儘量統一管理。
    2. 有提供 api 可呼叫,參考這裡,如果要做自動化的人可以來弄弄。
  • Cloudflare Workers 服務介紹

    如果有使用 cloudflare 服務,需要 serverless 功能的話,可以評估使用量來使用 cloudflare 的 workers 服務。參考:

    Cloudflare Workers documentation · Cloudflare Workers docs
    Documentation for Cloudflare Workers, a serverless execution environment that allows you to create entirely new applications or augment existing ones without configuring or maintaining infrastructure.

    他可以作為 client to server 的 middleware 或是當作是一個終端。 serverless 的服務各大 vps 商也都有,像是 AWS GCPAzure 等,這裡也有篇 Linode 關於 Serverless Computing 的優缺點介紹

    值得一提的是他還有 wokers router 服務,以及 workers KV 服務,提供了路由和儲存的實作,有興趣可以玩玩看。另外在 workers 的設定中,如果同一個帳號中也有使用 name server 的服務,可以調整自定義網域的作法,將子域名指定過去,這樣就不用記很奇怪的域名啦。

    Cloudflare 的 workers 服務有提供免費以及付費的方案,參考介紹頁面底下的表格,細節計算可以參考:

    Pricing · Cloudflare Workers docs
    By default, users have access to the Workers Free plan. The Workers free plan includes limited usage of Workers, Pages Functions and Workers KV. Read …

    Workers 使用的語言比較偏向 nodejs ,可用的應用場景滿多的,可以參考官方文件範例
    像是如果需要做一個簡單跳轉,可以這樣寫:

    const base = 'https://example.com';
    const statusCode = 301;
    
    async function handleRequest(request) {
      const url = new URL(request.url);
      const { pathname, search } = url;
    
      const destinationURL = base + pathname + search;
    
      return Response.redirect(destinationURL, statusCode);
    }
    
    addEventListener('fetch', async event => {
      event.respondWith(handleRequest(event.request));
    });
    

     

    同場加映其他介紹文章:

    Cloudflare Workers入門 ─ 簡介
    Cloudflare Workers將送進來的request在cloudflare的網絡上做處理。你可以把它放在client和server的中間,用做Middleware;後方也可以沒有server ─ …

    tool man xyz
    此網站版面極為簡潔,內容包含不好笑又尷尬的文章、覺得之後可能會看所以先保存但事後很少會看的新聞等。