お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。
投稿日:
ネットワーク::HTTP

日頃仕事で開発をしていたり、そこら辺の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をサーバー側が設定するので、このリクエストには意味がない。トラフィックと実装コードの無駄といえる。

サーバー側が何を基にして設定しているかは実装依存だと思うが、恐らく一般的にはトランスポート層より下ではないだろうか?

あとがき

いわゆるフロントエンドエンジニアや、プログラミングスクール卒などの意識が低いエンジニアらが書いたコードを見ているとこのようなものが散見される印象だが、もう少しちゃんと考えて実装して欲しいと思う。

なんというか、最低限常識とされている部分は理解しておいてほしいなというのはすごく思う。

投稿日:
ネットワーク::HTTP言語::PHPNode.js::その他

動機としては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が応答された。

確認環境

Env Ver
ルーター YAMAHA RTX830
ファームウェアRev. Rev.15.02.26 (Wed Sep 7 12:36:21 2022)

やり方

まず以下のコマンドで対象のIPv6アドレスとポート番号を指定する。IPv6アドレスの取得方法は後述する。

ipv6 filter 静的フィルター番号 pass * 宛先IPv6アドレス フィルタリングするパケットの種類 * 宛先ポート

次に次のコマンドで先ほど設定した静的フィルター番号を指定する。静的フィルター番号はデフォルトで設定されているものがあるはずなので、それに追記する形で行う。

ipv6 lan2 secure filter in 静的フィルター番号...

もし間違えて既存のフィルター番号を消し飛ばした場合はipv6 filterがついてる番号を列挙してやればよい。

IPv6アドレスの取得方法

以下のコマンドを叩くと取れる。もっといい方法があると思うのだがパッと見つからなかった。ifconfigを叩くと無数のアドレスが出てきてどれを選べばいいのかわからないが、軽く見た感じグローバル用とローカル用がごちゃ混ぜになっているようだった。

curl https://ifconfig.me

HTTPヘッダを持たないHTTPリクエストはあり得るのか?というのを検証しているときに気づいた話。

RFC 7230ではHostヘッダを持たないHTTPリクエストは禁止されており、これを受けたサーバーは400応答を返すことを必須としている。

RFC 7230:Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and RoutingHostより

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

手順

  1. Android端末のストレージにエクスポートしたCA証明書を持ってくる
  2. 設定>セキュリティ>その他のセキュリティ設定>ストレージからインストール>CA証明書>このままインストール
  3. 内部ストレージからエクスポートしたCA証明書を選択

Windows

確認環境

Windows 11 Pro (22621.3155)

手順

  1. スタートメニューやコンパネから「ユーザー証明書の管理」を開く
  2. 信頼されたルート証明書を右クリックし、すべてのタスク>インポート
    信頼されたルート証明書を右クリックし、すべてのタスク>インポート
  3. エクスポートしたCA証明書を参照する
    エクスポートしたCA証明書を参照する
  4. 証明書ストアが「信頼されたルート証明機関」になっていることを確認する
    証明書ストアが「信頼されたルート証明機関」になっていることを確認する
  5. 取り込む証明書が正しいことを確認して「はい」
    取り込む証明書が正しいことを確認して「はい」

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