はじめに
目的
- 競技プログラミングの経験が活きるケースの一例を示したいから
- 加えて、競技プログラマーはセキュリティエンジニアの適性が一定あるのではないか、と思っているから
- 自分は学生時代セキュリティエンジニアという職業の存在すら知らなかったから
- そもそも研究と競プロしかしてなかったのでほぼ開発経験がなかった
「へー、セキュリティの仕事なんてあるんだ。コーナーケースを指摘することが仕事になるんだ。」
ってことが伝われば幸いです。
もちろん、コーディング力やコードを読む力、というのが役に立つのは、ここでは比較的自明なので特筆していません。
セキュリティでどんなことやってるのか
ここに書いていることをやってました。
2014年から新卒でセキュリティの仕事を始めました。
- https://www.slideshare.net/dena_tech/ss-87959976
- https://www.slideshare.net/linecorp/ss-78078614
- https://fullswing.dena.com/archives/3075
競技プログラマーの得意なこととセキュリティ業務
コーナーケースの洗い出しと脆弱性診断
競技プログラマーの皆さん、コーナーケース考えるの好きじゃないですか?
私の周りでは普段でもボードゲームを始めるためにルールを読むと、まず最初にゲームが終了しなくなる条件を考え出したり、
次のアクションが決定できないようなコーナーケースを考え始める人も少なくない気がします!
やはり、そもそも問題を正しく理解すること、あるいは、自分の解法を正しく理解することに、コーナーケースへの理解が含まれてますよね。
文字列を操作するときには、空文字列をどう扱うか気になるし、
グラフを扱うときは、グラフが連結でないとき何を出力するか気になるし、
実はグリッド上で同じマスを2回通るほうが解が改善するコーナーケースがあったり。
すべてのテストケースで正しい解を出すことに集中している皆さんは、コーナーケースに敏感だとおもいます。
脆弱性診断は実際にリリースするWebサービスにへんなパラメータを送ってバグらせる仕事です。
こどふぉのHack, SRMのチャレンジに近いものがあります。
少し、コーナーケースとはズレるものがあるのですが
例えば、
- メールアドレスの登録がまだされていない状態でメール送信を伴う機能(パスワード復旧等)を使ってみる、とか
- 商品購入機能で、値段x個数がintがちょうどオーバーフローして負になってしまう個数、商品を購入する、とか
- そもそも負の数や小数を個数に指定してみる、とか
- 重要な機能は追加認証を行わないと使えないが、追加認証の設定を基本的な認証だけで変えてバイパスするとか。
- 下記スライドの12ページや17ページを参照
こういった"バグりそうなケース"を考えるのって楽しいですし、それがお仕事になるなら最高ではないでしょうか?
私は実際にこういった業務が競プロerは楽しめる、かつ、得意である、のではないかと考えています。
実際にサービスのコードを読みながらバグりそうな入力を探すことも多いです。
コードを読んでバグを探す、というのは得意なところですよね。
計算量の見積もりとセキュリティレベル
プロコンの問題を解くうえで、意識するのは計算量かと思います。
自分が考えている解法のどの部分が支配的かを判断し、そこに注目しどう落としていくか、等を考えていきますよね。
そういった考え方と似た考え方にセキュリティレベルの考え方があります。
サービス一つ攻撃するにあたって、攻撃シナリオは無数にあります。
そのシナリオの中で一番弱いものが支配的なセキュリティレベルになります。
そこに注目して改善しようとしたり、同等のものを洗い出したりしているときに、なんだか計算量を落とすときの作業みたいだなと感じることがあります。
Webサイトなら例えば、
- IDとパスワードが漏洩してしまったユーザを完全に乗っ取りされないよう守りたい。
- リスト型等の攻撃を受けたとき、ユーザが自分自身で復帰できるようにしたい。
- じゃあ、攻撃者に簡単にパスワードを変更できないようにしよう。
- パスワードを変更するには、登録したメールアドレスに認証コードを送ってそれを入力しないとパスワードを変更できないようにしよう。
という機能を実装するとします。
この場合、パスワードの変更ができるのは、「IDとパスワードを知っていて、かつ、登録済みメールアドレスのメールを読める人」となり、相当攻撃が難しくなります。
不正ログイン・利用された場合、パスワードが変更されていないため、まだユーザ自身が気付き次第対応ができるという状態になります。
そのように見えるのですがサービス全体を見た場合に、
- パスワードを忘れた人向けに復旧機能がある。登録済みメールアドレスに復旧用URLが送らるので、それをクリックすると復旧できる
という機能があったとします。
この機能の存在により、パスワードを変更できる条件は、
「登録済みメールアドレスのメールが読める人」
単体になりますね。
さらに、メールアドレス変更機能があったらどうでしょうか?
- IDとパスワードでログイン後、メールアドレスが変更できる
パスワードを変えたい攻撃者は、
- 漏洩したID/パスワードでログイン
- => パスワードを変更しようとしたが認証コードのメールが受信できない
- => 先にメールアドレスを変更する
- => 認証コードが受信できるのでパスワードを変更できる
といった経路で完全な乗っ取りができてしまいますね。
これで、パスワードを変更できる条件は、
「登録済みメールの到達性がある」or「現在のID/パスワードを知っている」
となります。
そのため今回目指すセキュリティレベルを達成するには、メールアドレスの変更に旧メールアドレスへの到達性を確認しなければ、導入する意味がない、ということになります。
このように、今何がサービスのセキュリティレベルを担保してるんだっけ?ということを意識するときに、一番セキュリティレベルの低いフローが支配的になります。
その底上げをしていくことがセキュリティレベルの向上につながります。
私はこれが計算量を落とすときの支配的な計算量に注目するのと似たイメージを持っています。
こういうの考えるの、おもしろくないですか?
さいごに
なんだ、直接競技プログラミングのアルゴリズムを使うという話じゃないのか!と思われた方すいません。
確かに、そういった場面がすごく多いわけではありません。
ですが、学生時代に真剣にプロコンの問題に向き合ってきたからこそ、多くのセキュリティレベルのバイパスや挙動がおかしくなるコーナーケースを発見できたと私は考えています。
こういった例は今後ほかのエンジニアリング分野でも多く報告されていくと思いますが、
競技プログラマーのキャリアの選択肢の一つとしてセキュリティエンジニアが挙がってくるとうれしいなと思います。