- 投稿日:
WSL上のUbuntuで動作するnginxでHTTPSに対応したサーバーを作る方法。実機でも同様の手順でいける
確認環境
Env | Ver |
---|---|
nginx | nginx/1.18.0 (Ubuntu) |
mkcert | v1.4.4 |
Ubuntu | 20.04.6 LTS |
Windows 11 | 22621.3880 |
手順
- Windows側にmkcertを入れる
- mkcertで証明書を作る
mkcert sandbox.test
- 以下のpemファイルが生成される
sandbox.test.pem
sandbox.test-key.pem
- 生成されたpemファイルを
/etc/nginx/conf.d/ssl/
に移動する /etc/nginx/conf.d/sandbox.test.conf
を作成し、以下のような記述をするserver { listen 443 ssl; client_max_body_size 100m; server_name sandbox.test; ssl_certificate conf.d/ssl/sandbox.test+1.pem; ssl_certificate_key conf.d/ssl/sandbox.test+1-key.pem; access_log /var/log/nginx/sandbox.access.log; error_log /var/log/nginx/sandbox.error.log; # ファイルホスト用 # location / { # root /usr/share/nginx/html/sandbox; # index index.html; # try_files $uri /index.html =404; # } # APサーバーへのリバプロ用 location ~ ^/.*$ { rewrite ^/.*$ / break; proxy_set_header X-Request-Path $request_uri; proxy_set_header X-Host $host; proxy_pass http://127.0.0.1:9999; } # fastcgi用 location ~ \.php$ { root /usr/share/nginx/html/sandbox; fastcgi_pass unix:/run/php/php8.0-fpm.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }
- nginxを再起動する
sudo service nginx restart
他の端末に証明書を撒く方法
mkcertのRoot CAをエクスポートして他の端末に突っ込めば、他の端末でもpemが流用できる
- 投稿日:
日頃仕事で開発をしていたり、そこら辺のWebサービスの振る舞いを眺めていると不思議というか、奇妙というか、端的に言うとありえないリクエストを投げているものを見かける。
一例としては次のようなものを見たことがある。
フロントエンドで第三者サービスに問い合わせクライアントIPを取得し、それをバックエンドに送る
これの問題点はまずクライアントのIPを幾らでも捏造できることだ。
クライアントからバックエンドに投げている値など幾らでも偽装できるため、その中にクライアントのIPアドレスを含めるのは何の価値もない。
他にも第三者のサービスを利用しているので、そこが落ちてたり、仕様変更があったりすると使えなくなる。
サーバー間のHTTP通信でクライアントのIPをREMOTE_ADDRヘッダーに入れて送る
具体的にはSSRを利用しているNext.jsのサーバーサイドレンダリング側で、クライアントのIPを取得し、後ろにいるAPサーバーにHTTPで投げるときにREMOTE_ADDRヘッダーに入れて送っていたケースだ。curlで表すと次のような形式だ。
curl -H 'REMOTE_ADDR: <ここにIP>' http://example.com
サーバー側はクライアント側のIPをサーバー側が設定するので、このリクエストには意味がない。トラフィックと実装コードの無駄といえる。
サーバー側が何を基にして設定しているかは実装依存だと思うが、恐らく一般的にはトランスポート層より下ではないだろうか?
あとがき
いわゆるフロントエンドエンジニアや、プログラミングスクール卒などの意識が低いエンジニアらが書いたコードを見ているとこのようなものが散見される印象だが、もう少しちゃんと考えて実装して欲しいと思う。
なんというか、最低限常識とされている部分は理解しておいてほしいなというのはすごく思う。
- 投稿日:
動機としてはcurlだと見えない部分があるので、自分でHTTPメッセージを手組みして送ってみたかった。
Node.jsとPHPのサーバーでリクエストが期待通り取得できたので、メッセージの実装としては問題ないと思われる。
検証用サーバー
以下のコードをNode.js v20.11.1を用いて検証
import http from 'node:http';
http
.createServer((req, res) => {
console.log(req.headers);
req.on('data', (chunk) => {
// body
console.log(Buffer.from(chunk).toString());
});
res.statusCode = 200;
res.end();
})
.listen(9999);
netcatコマンドによるリクエスト検証
GETリクエスト
echo -e 'GET / HTTP/1.1\r\nHost: localhost:9999\r\n\r\n' | nc localhost 9999
POSTリクエスト
echo -e 'POST / HTTP/1.1\r\nHost: localhost:9999\r\nContent-Length: 4\r\n\r\nhoge' | nc localhost 9999
備考
PHPで検証サーバーを作る場合
実際にAPサーバーでリクエストの中身をパース出来るかどうかの観点で見た場合にNode.jsよりPHPのが楽なので、PHPで作ってみた結果、軽くハマったので残しておく。
以下のコードを用いてPHP 8.0.29で検証サーバーを作る場合に、php -S 0.0.0.0:9999
としてサーバーを起動すると、Content-Type
ヘッダがない場合に正常な動作をしなかった。
<?php
var_dump($_SERVER);
var_dump($_REQUEST);
ncで検証サーバーを作る場合
デバッグ用。生のメッセージが見れるのでダンプしてdiffを取るなどでcurlとecho + ncの差分を見るのに使える。
nc -l 9999
HTTPメソッド名を非標準的なものにした場合の挙動
前述のNode.jsサーバーでは400 Bad Request
、PHPサーバーでは501 Not Implemented
が応答された。
- 投稿日:
HTTPヘッダを持たないHTTPリクエストはあり得るのか?というのを検証しているときに気づいた話。
RFC 7230ではHostヘッダを持たないHTTPリクエストは禁止されており、これを受けたサーバーは400応答を返すことを必須としている。
RFC 7230:Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and RoutingのHostより
A client MUST send a Host header field in an HTTP/1.1 request even if
the request-target is in the absolute-form, since this allows the
Host information to be forwarded through ancient HTTP/1.0 proxies
that might not have implemented Host.
A server MUST respond with a 400 (Bad Request) status code to any
HTTP/1.1 request message that lacks a Host header field and to any
request message that contains more than one Host header field or a
Host header field with an invalid field-value.
なお、Node.jsのHTTPサーバー機能ではHostヘッダーのない要求を受け入れることができる。
http.createServer([options][, requestListener])を見ると、以下のようにrequireHostHeader: false
を渡すことで実現可能だ。規定値はtrue
であるため、基本的にはHostヘッダーなしの要求は400応答が返される。
import http from 'node:http';
http
.createServer({requireHostHeader: false}, (req, res) => {
console.log(req.headers);
res.statusCode = 200;
res.end();
})
.listen(3000);
nginxにおいてもHostヘッダーなしの要求は以下の応答が返されたため同様と思われる。
<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/1.26.0</center>
</body>
</html>
但し、nginxにおいてHostなしの要求を許容する方法は見つからなかった。Server namesによるとserver_name "";
とすることで出来そうに見えたが、これは機能させることができず、400応答が返された。
- 投稿日:
mkcertで作ったCA証明書をエクスポートする方法でエクスポートしたCA証明書を他の端末に取り込む方法
Android
確認環境
Galaxy S22 Ultra Android 14
手順
- Android端末のストレージにエクスポートしたCA証明書を持ってくる
- 設定>セキュリティ>その他のセキュリティ設定>ストレージからインストール>CA証明書>このままインストール
- 内部ストレージからエクスポートしたCA証明書を選択
Windows
確認環境
Windows 11 Pro (22621.3155)
手順
- スタートメニューやコンパネから「ユーザー証明書の管理」を開く
- 信頼されたルート証明書を右クリックし、すべてのタスク>インポート
- エクスポートしたCA証明書を参照する
- 証明書ストアが「信頼されたルート証明機関」になっていることを確認する
- 取り込む証明書が正しいことを確認して「はい」
Ubuntu
確認環境
Ubuntu 22.04.3 LTS
手順
$CER_FILE="エクスポートしたCA証明書"
sudo openssl x509 -inform der -outform pem -in $CER_FILE -out PEM.crt
sudo cp PEM.crt /usr/local/share/ca-certificates
sudo update-ca-certificates