はじめに
以下の記事にこんなコメントがありました。
UA ブロック程度で拒否できるほど生成 AI 事業者って技術レベル低いのかな?
コメントより
Python かじればすぐ分かるけど、その程度ならすぐ対応できると思うよ。
UA の偽装はやってみたことがないので、「試せる環境が欲しいな!」と思って以下の Docker 環境を用意しました。(後述)
ちなみに UA 偽装はわりと簡単にできました。
最近、有名な企業の Bot によるサイトダウンの事例を聞くことが多いですが、もしかしたら Bot 名もバンバン偽装されているのかもしれませんね。
利用するファイル情報
- ディレクトリ構造
.
├── app
│ ├── Dockerfile
│ └── app.py
├── compose.yml
└── nginx
├── Dockerfile
├── conf.d
│ └── default.conf
└── logs //コマンド実行後に作成される
├── access.log
└── error.log
- 利用するファイル
# compose.yml
services:
nginx:
build:
context: ./nginx
dockerfile: Dockerfile
ports:
- "8080:80"
volumes:
- ./nginx/logs:/var/log/nginx
- ./nginx/conf.d:/etc/nginx/conf.d
depends_on:
- app
app:
build:
context: ./app
dockerfile: Dockerfile
expose:
- "5000"
# ./nginx/Dockerfile
FROM nginx:alpine
RUN mkdir -p /var/log/nginx
RUN touch /var/log/nginx/access.log /var/log/nginx/error.log
# ./nginx/conf.d/default.conf
server {
listen 80;
server_name localhost;
access_log /var/log/nginx/access.log combined;
error_log /var/log/nginx/error.log;
location / {
proxy_pass http://app:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header User-Agent $http_user_agent;
}
}
# ./app/Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY . /app
RUN pip install flask
EXPOSE 5000
CMD ["python", "app.py"]
# ./app/app.py
from flask import Flask, request
import json
app = Flask(__name__)
@app.route('/')
def index():
user_agent = request.headers.get('User-Agent')
response = {
'user_agent': user_agent,
'headers': dict(request.headers)
}
return json.dumps(response, indent=2)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
- 利用するコマンド
docker-compose up --build
アクセス結果
上記で起動したサーバーhttp://localhost:8080に対してのアクセス結果を記載します。
ブラウザアクセス:safari 18.3
- ブラウザ上の表示
{
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15",
"headers": {
"Host": "localhost",
"X-Real-Ip": "172.19.0.1",
"X-Forwarded-For": "172.19.0.1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15",
"Connection": "close",
"Sec-Fetch-Dest": "document",
"Upgrade-Insecure-Requests": "1",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Sec-Fetch-Site": "none",
"Sec-Fetch-Mode": "navigate",
"Accept-Language": "ja",
"Priority": "u=0, i",
"Accept-Encoding": "gzip, deflate"
}
}
- Nginx のアクセスログ
172.19.0.1 - - [22/Feb/2025:05:42:59 +0000] "GET / HTTP/1.1" 200 729 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15"
ブラウザアクセス:Chrome 133.0.6943.127
- ブラウザ上の表示
{
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
"headers": {
"Host": "localhost",
"X-Real-Ip": "172.19.0.1",
"X-Forwarded-For": "172.19.0.1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
"Connection": "close",
"Sec-Ch-Ua": "\"Not(A:Brand\";v=\"99\", \"Google Chrome\";v=\"133\", \"Chromium\";v=\"133\"",
"Sec-Ch-Ua-Mobile": "?0",
"Sec-Ch-Ua-Platform": "\"macOS\"",
"Upgrade-Insecure-Requests": "1",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Sec-Fetch-Site": "none",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-User": "?1",
"Sec-Fetch-Dest": "document",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Accept-Language": "ja,en-US;q=0.9,en;q=0.8"
}
}
- Nginx のアクセスログ
172.19.0.1 - - [22/Feb/2025:05:43:50 +0000] "GET / HTTP/1.1" 200 980 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36"
ブラウザアクセス:Googlebot 偽装(やり方は後述リンク参照)
- ブラウザ上の表示
{
"user_agent": "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
"headers": {
"Host": "localhost",
"X-Real-Ip": "172.19.0.1",
"X-Forwarded-For": "172.19.0.1",
"User-Agent": "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
"Connection": "close",
"Upgrade-Insecure-Requests": "1",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Sec-Fetch-Site": "none",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-User": "?1",
"Sec-Fetch-Dest": "document",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Accept-Language": "ja,en-US;q=0.9,en;q=0.8"
}
}
- Nginx のアクセスログ
172.19.0.1 - - [22/Feb/2025:05:35:31 +0000] "GET / HTTP/1.1" 200 744 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
Curl でのチェック
{
"user_agent": "curl/8.7.1",
"headers": {
"Host": "localhost",
"X-Real-Ip": "172.19.0.1",
"X-Forwarded-For": "172.19.0.1",
"User-Agent": "curl/8.7.1",
"Connection": "close",
"Accept": "*/*"
}
}
- Nginx のアクセスログ
172.19.0.1 - - [22/Feb/2025:05:29:25 +0000] "GET / HTTP/1.1" 200 224 "-" "curl/8.7.1"
UA を偽装したCurl
curl -A "Custom User Agent" http://localhost:8080
- コンソール上の表示
{
"user_agent": "Custom User Agent",
"headers": {
"Host": "localhost",
"X-Real-Ip": "172.19.0.1",
"X-Forwarded-For": "172.19.0.1",
"User-Agent": "Custom User Agent",
"Connection": "close",
"Accept": "*/*"
}
}
- コンソール上の表示 Nginx のアクセスログ
172.19.0.1 - - [22/Feb/2025:05:44:45 +0000] "GET / HTTP/1.1" 200 238 "-" "Custom User Agent"
UA 偽装で参考にした記事
最後に
UA 偽装用に用意しましたが、普通に UA チェック用で利用できますね。
またUAに依存するようなシステム構成のリスクがわかり個人的に有益な経験でした。
Bot対策としてはaws等がマネージドなサービスを(WAF系)を提供しているので、積極的に利用していきたいですね。
以上、どなたかのお役に立てば幸いです。