はじめに
こんにちは。わいけい(https://x.com/yk_llm_gpt )です。
今回の記事はセキュリティに関して書きます。
スタートアップや個人開発などの小規模チームではセキュリティの専門部署が存在していることは稀です。
そういった環境ではアプリケーションを開発しているエンジニアが自分たちのアプリケーションに脆弱性を埋め込まないように責任を持つ必要があります。
そういった方々の参考になるように、この記事では自分がアプリケーションを公開する前にセキュリティ面で特に注意を払っている点についてまとめました。
なお、実践的になるように、教科書的な広く浅い内容ではなく、あえて現実の攻撃者の目線を盛り込んだ特定領域の内容にしています。
私のSNSアカウント等です。
今後もPython・LLM・Go・Web開発などのトピックについて発信していくのでフォローしていただけると喜びます。
X: わいけい
LinkedIn: ykimura517
Github: ykimura517
そもそも攻撃者は何をしてくるのか
セキュリティについて考えるときは、クラッカー(攻撃者)の気持ちになることが大切です。
Webアプリ作成の入門本などでセキュリティについて学んでいると、「SQLインジェクションを防ぐには」「XSS脆弱性を埋め込まないためには」といった内容が並べられていることが多いです。
しかし、実際にあなたが何かしらのサイトに侵入したいと考えている場合、一つ一つ知っているサイトのフォームに対してSQLインジェクションができるかトライしてみるでしょうか。
考えただけでもかなり効率が悪そうですね。
クラッキング成功時の利益が非常に大きいサービス(例えば暗号資産の取引所など)であれば、そういった「丁寧な」攻撃を行う意味もあるかもしれません。
しかし大半のWebサービスの場合、攻撃者的にも一つ一つ手間をかけて調査していくのは労力に見合いませんね。
一つ一つのサービスをじっくり見る前に、例えば次のような方法を試すのではないでしょうか。
- まずAWSなどのメジャーなクラウドサービスが保有するIPアドレス帯をリスト化する
- 各IPに対してポートスキャンを行って良さげなポートが開放されているかチェックする
- 各IPに対し、http(80)、https(443)などのポートが開いている場合、次は
/.env
などのリクエストが通らないかチャレンジしてみる - その後、sshやWebサービスのアカウントなどで何らかの方法でユーザー名が推測できそうなものに関してはパスワード総当たりなどでログインできないかチャレンジしてみる
「じっくり丁寧に」攻撃を仕掛けるのではなく機械的にスキャンした方が効率はよさそうですね。
ちなみに、クラウドサービスが保有するIPアドレス帯に順次攻撃を仕掛けることができるサービス(と言っていいのか)なども存在しています。
また、開放されているポートの調査については、nmap
コマンドなどで調査することが可能です。
例えばsample.com
(IPアドレスでも可)が開放しているポートを知りたければ
nmap sample.com
を実行します。
これでそのサーバーがガバガバになっていそうかどうかをチェックすることが可能です。
(試しに自分のサービスのドメインをチェックしてみるといいでしょう)
攻撃者は、ポートスキャンの結果、例えばRDP(リモートデスクトップ)のポートが空いているのであれば、そのリモートデスクトップサーバーのバージョンなどから脆弱性がないか検索します。
世の中には脆弱性を検索できるサービス(例えばExploit Databaseなど)があるので、
- そもそもの脆弱性の有無
- 脆弱性がある場合は具体的にどういうことができるか
を調べることができます(勿論悪用NGです)。
他にもnmapの結果、httpやhttpsでのアクセスができそうであれば、リクエストを行うことでサーバーに残された認証周りの情報を取得できないかチャレンジしてみたくなるかもしれません。
実際にAWSなどでサービスを公開すると、公開した瞬間から
/.env
/.aws/config
といったパスにGETリクエストが飛んでくると思います。
これは、攻撃者が本来公開サーバーに残してはいけない(万一何らかの事情で残さざるを得なかったとしても絶対にパブリックにしてはいけない)情報をダメ元で取得しようとしていることによって発生しています。
たまに「自分のサービスなんて知名度も低いからそもそも攻撃者に発見されないだろう」という風に思っている人がいます。
しかし現実には、AWSなどを使ってホスティングしている場合、サービスの規模によらず攻撃対象になっています。
※こう書くと、一部の読者に対して「クラウドは使うの危険そう」という印象を与えている可能性があります。
が、個人的にはオンプレよりもクラウドの方がセキュリティを担保しやすいと思っています。
- WAFなどセキュリティ特化のサービスを活用しやすい
- クラウドの各種マネージドサービスを使うことで、不要な認証情報ファイル等が公開サーバーに紛れ込むリスクが下がる
などが理由です。
極論、例えばオンプレでWebサーバーを構築している際にsshの認証情報をそのサーバーに設置するケースがあると思います。
しかしLambdaやECSを使ってWebサービスを公開する場合、そもそもそのような事態は起きません。
まあ実際にはオンプレだろうがクラウドだろうが脆弱性が埋め込まれるかどうかは開発者の腕次第ではあります。
しかし、多くの人にとっては、クラウドの方がセキュアなサービスを楽に構築できるのではないかと個人的には思っています。
話を戻します。
次はログインパスワードの総当たりについてです。
例えば脆弱性のありそうなサーバーが見つかったとして、そのサーバーがhttp(80番ポート)とssh(22番ポート)が公開していたとします。
さらに/.env
に対してリクエストを送ってみると、なんと200で応答が帰ってきたとしましょう。
結果、.env
の内容に
USERNAME=takeda
などの情報が記載されていたとします。
そうすると多くの人は、sshで takeda@サーバーのIP
にログインしたくなるのではないでしょうか。
全体的にガバガバなサーバーなので、パスワードもいい加減に設定している可能性が高そうです。
世の中にはよく使われるパスワードをまとめたもの(有名なものにrockyou.txt
などがあります)が公開されています。
実際に辞書攻撃を行うにはhydra
などのツールを使うことが多いと思います。
例えば
hydra -l takeda -P {rockyou.txtのパス} ssh://{サーバーのIP}
といったコマンドを打つことで総当たりでログインできないか試すことができます。
もちろん
- そもそもSSHのユーザー名が
takeda
ではなかった -
rockyou.txt
に載っているパスワードを使っていなかった
というケースであれば、ログインできません。
(しかし、逆に言えばユーザー名がtakeda
であり、rockyou.txt
に載っているパスワードを使っていた場合、これでログインできてしまいます。)
以上、世の中の攻撃者の気持ちになってみました。
サーバーに侵入を試みる際はおおよそ先述したような試行をすることが多いのかなと思います。
チェックすべきセキュリティ周りのポイント
それでは、ここからはサービス公開前にチェックすべきセキュリティ周りのポイントについて考えていきましょう。
そもそも攻撃者は、機械的に脆弱性のあるサイトをスキャンしようとしています。
このスキャンの対象になること自体はサービスを公開している以上避けることはできません。
しかし、スキャンの結果、攻撃者の注意を引かないことが重要です。
こういった観点からサービス公開時にどういった点に注意しなければいけないかを見ていきましょう。
余計なポートが開いていないか
まずは不要なポートが開いていないかチェックします。
Webサービスなら80番と443番ポートに代表されるようなhttp周りのポートを開けていると思います。
このほか余分なポートは必要ない限り閉じておきましょう。
具体的にはAWSを使っているならセキュリティグループの設定を見直すことで必要ポート以外のアクセスを遮断することができます。
望まないリクエストが到達できないようになっているか
また、サービスに必要ないパスへのリクエストは遮断するようにしましょう。
こちらもAWSを使っている場合はクラウドフロントやWAFの設定で/.env
などのやばそうなパスへのリクエストを弾くことが可能です。
簡易的ですがアプリケーションサーバーの前にnginxなどのリバースプロキシが立っている場合、そちらの設定でアプリケーションサーバーの手前で弾くことも一応できます。
使用ツールは最新か
重要なのが使用しているライブラリやミドルウェアなどを最新に保っておくことです。
サーバーが使用しているツールが特定できれば、Exploit Databaseなどで脆弱性の有無を調べることができることは先述しました。
フレームワークなどは極力最新のものを使いましょう。
開発にGitHubを使っているのであればDependabot
を導入するのもおすすめです。
Dependabot
は、プロジェクトの依存関係を自動的に更新するGitHubのツールで、セキュリティの脆弱性が発見された依存関係や、新しいバージョンがリリースされた際にプルリクエストを自動的に作成してくれます。
サーバー上に不要なファイルが残っていないか
AWSのcredential情報や.env
ファイルなどを極力本番サーバーに混入させないようにしましょう。
(運用上必要な秘匿情報などは環境変数化したり、AWSであればパラメーターストアに格納したりすると良いでしょう。)
特にありがちなのはDockerでのコンテナビルド時にホストマシンに存在する.env
ファイルをコンテナにコピーしてビルドしてしまうパターンです。
現実的にはその場合でも、コンテナに侵入されたり、その.env
が外から見えるようになっていなければ具体的に何かされることはないのですが、やめておきましょう。
こちらは.dockerignore
ファイルで秘匿情報ファイルを指定することで回避できます。
パスワードの強度は適切か
重要なのがパスワードの強度を強めにしておくことです。
こちらはユーザーに求めるパスワード、開発者が使うパスワード双方に言えることです。
とにかく先述したrockyou.txt
などのクラッカーがよく使う辞書に載っていないパスワードを使うことが重要です。
IP制限は適切か
全世界に公開する必要がないサービスを作る場合もあるでしょう。
例えばB2B向けのサービスで、顧客の特定の事業所のみからアクセスするといったケースですね。
そういった場合はIP制限をかけておくのが望ましいです(というか顧客の側から要求してくるケースも多いでしょう)。
こちらもAWSを使っている場合はセキュリティグループからの設定が可能です。
顧客側のIPアドレスが固定されていない場合は、残念ながらどうしようもないです。
まとめ
今回の記事では
- クラッカー目線に立った攻撃の手法の概要
- それに基づいたセキュリティチェック項目
について触れてきました。
とはいえここまで読んだ方は感じておられると思いますが、ここであげたポイントを全て網羅したからと言ってセキュアなアプリケーションだと胸を張れるわけでは全くありません。
あくまで最低限攻撃者の目に留まりづらくするための最初のステップに過ぎません。
これらを固めた上でアプリケーション側のセキュリティ対策もしっかりやっていかねばなりません。
考えることが多くて嫌になりますね。
しかし近年ニコニコ動画が大規模サイバー攻撃を受けて巨額の損失を出した事件からも明らかなように、セキュリティ面は本当にしっかりやっておかないと大きな後悔をすることになりかねません。
なので、お互い頑張っていきましょう!
ちなみに、もしセキュリティについて相談に乗って欲しいという企業様がいれば、どうぞお気軽にご相談ください。
弊社では、スポットのセキュリティコンサルやセキュアなバックエンド開発のご相談を随時受付中です。
(ただし基本的に個人運営の会社なのでリソース的に必ず対応できるとは限りません。あらかじめご了承ください)
今後もWeb開発やLLMに関する発信を行っていく予定なので今回の記事が少しでも役立ったという方は、私のSNSなどをフォローしていただけると大変喜びます。
X: わいけい
LinkedIn: ykimura517
Github: ykimura517