使用Cloudflare Workers託管MTA-STS.txt檔案

MTA-STS縮寫為Mail Transfer Agent-Strict Transport Security,目的是強化SMTP的連線安全性,可以參考Google文件〈關於MTA-STS和傳輸層安全標準(TLS)報告〉的說明。因為我自己是用iCloud自訂電子郵件網域,需自行設定才能支援MTA-STS。

MTA-STS的詳細設定請參考〈How to Set Up MTA-STS and TLS Reporting to Identify and Fix Email Security Issues〉,其中MTA-STS.txt通常是放在自己的主機,但有些網友則是將MTA-STS.txt託管在Cloudflare Workers。

步驟如下:

  1. 到Cloudflare Workers新增一個應用程式,程式碼參考〈MTA-STS Cloudflare worker〉,只有前面幾行的網域和MX名稱要改:
    // This worker is designed to be able to neatly handle MTA-STS policies for multiple domains.
    
    // Make a new worker with this script and add your domains to the stsPolicies dict like the example.
    // Add a DNS AAAA record for mta-sts.yourdomain.com pointing to 100:: and set to proxied,
    // then add a workers route for mta-sts.yourdomain.com/* pointing to this worker.
    
    // You should probably also create a Cloudflare configuration rule disabling Browser Integrity Check for the mta-sts subdomain
    // to ensure MTAs aren't blocked from retrieving your policy.
    
    // You'll still need to manually add the appropriate _mta-sts.yourdomain.com TXT record to enable the policy,
    // and the _smtp._tls.yourdomain.com TXT record for reporting.
    
    const stsPolicies = {
      "mynet.tw":
    `version: STSv1
    mode: enforce
    mx: mx01.mail.icloud.com
    mx: mx02.mail.icloud.com
    max_age: 86400`
    }
    
    
    const respHeaders = {
      "Content-Type": "text/plain;charset=UTF-8",
      "X-Clacks-Overhead": "GNU Terry Pratchett, Jon Postel, Alan Turing, Dan Kaminsky"
    }
    
    addEventListener("fetch", event => {
      event.respondWith(handleRequest(event.request))
    })
    
    async function handleRequest(request) {
      const reqUrl = new URL(request.url)
    
      if (!reqUrl.hostname.startsWith("mta-sts.")) {
        return new Response(`Incorrect worker route. mta-sts policies must be served on the mta-sts subdomain\n`, {status: 500, headers: respHeaders})
      }
    
      const policyHost = reqUrl.hostname.slice(8)
    
      if (!stsPolicies.hasOwnProperty(policyHost)) {
        return new Response(`${policyHost} is not defined in the mta-sts worker\n`, {status: 500, headers: respHeaders})
      }
    
      if (reqUrl.protocol !== "https:" || reqUrl.pathname !== "/.well-known/mta-sts.txt") {
        reqUrl.protocol = "https:"
        reqUrl.pathname = "/.well-known/mta-sts.txt"
        return Response.redirect(reqUrl, 301)
      }
    
      return new Response(stsPolicies[policyHost] + "\n", {status: 200, headers: respHeaders})
    }
    
  1. 上面的程式碼,支援多網域,前面幾行可以這樣改:

    const stsPolicies = {
      "yourdomain1.com":
    `version: STSv1
    mode: enforce
    mx: mail.yourdomain1.com
    mx: mailsec.yourdomain1.com
    max_age: 86400`,
      "yourdomain2.com":
    `version: STSv1
    mode: enforce
    mx: mail.yourdomain2.com
    max_age: 86400`
    }
    
  2. DNS新增AAAA紀錄,要開Proxy:

    mta-sts.mynet.tw IN AAAA 100::
    
  3. 在該網域新增一個Workers路由,內容如下:

    路由
    mta-sts.mynet.tw/*
    
    Worker
    your-mta-sts-workers.yourname.workers.dev
    
  4. 在該網域的WAF新增一個規則:

    完整URI 等於 https://mta-sts.mynet.tw/.well-known/mta-sts.txt
    

    運算式預覽如下:

    (http.request.full_uri eq "https://mta-sts.mynet.tw/.well-known/mta-sts.txt")
    

    再來是採取動作選擇跳過,要跳過的WAF元件選擇瀏覽器完整性檢查,最後點儲存。

  5. DNS新增MTA-STS TXT紀錄,id可以隨便取,1~32個英文字母和數字:

    _mta-sts.mynet.tw IN TXT "v=STSv1; id=12345678"
    
  6. DNS新增TLS-RPT(SMTP TLS Reporting) TXT紀錄,rua是接收報告的信箱:

    _smtp._tls.mynet.tw IN TXT "v=TLSRPTv1; rua=mailto:tlsrpt@mynet.tw"
    

最後用MTA-STS Validator驗證設定是否生效。