81
Webセキュア コーディングの基本 on 2013-09-15 13:00-13:50JST at PyCON APAC 2013 Room A0765 (Ja2) by OCHIAI, Gouji (@gjo)

PyCon APAC 2013 Web Secure Coding

Embed Size (px)

DESCRIPTION

Basics of Web Secure Coding on Python

Citation preview

Page 1: PyCon APAC 2013 Web Secure Coding

Webセキュアコーディングの基本

on 2013-09-15 13:00-13:50JSTat PyCON APAC 2013 Room A0765 (Ja2)

by OCHIAI, Gouji (@gjo)

Page 2: PyCon APAC 2013 Web Secure Coding

Abstract

• セキュアコーディングとは何か?

• Webシステムにおけるセキュリティ

• コード解説中心

• 基本的な内容しかやりません

• 「お前が言うな」は重々承知

Page 3: PyCon APAC 2013 Web Secure Coding

お前誰よ?• 落合 豪史

@gjo

• 一応職業プログラマーセキュリティの専門家とかではないです

• twitter.com/gjogithub.com/gjo

Page 4: PyCon APAC 2013 Web Secure Coding

本セッションおよび本稿の内容は私個人の見解であり、私の所属する企業、団体等とは一切の関わりはありません。

Page 5: PyCon APAC 2013 Web Secure Coding

The Year of Python

Page 6: PyCon APAC 2013 Web Secure Coding

Year of the Dragon

Page 7: PyCon APAC 2013 Web Secure Coding

心を入れ替えるよその方法を教えてくれ

Page 8: PyCon APAC 2013 Web Secure Coding

セキュアコーディングとは何か?

• 脆弱性に対して堅固なコーディング

• 脆弱性?

• 堅固?

http://www.flickr.com/photos/nene9/4444657449/

Page 9: PyCon APAC 2013 Web Secure Coding

セキュアな状態?• 一般的にセキュリティは非機能要件

• 「セキュリティが保たれていること」

• 実装に依存する要件

• 実装に依存しない要件

http://www.flickr.com/photos/jermainejustice/3352100979/

Page 10: PyCon APAC 2013 Web Secure Coding

実装に依存しないセキュリティ要件

• 「必要でない情報」を

• 「必要でない対象」に

• 「流通しない」

Page 11: PyCon APAC 2013 Web Secure Coding

実装に依存しないセキュリティ要件 (Cont.)

• 「必要な情報」を

• 「必要な対象」に

• 「流通する」

• 一般的な機能要件の逆

Page 12: PyCon APAC 2013 Web Secure Coding

相互作用を持たないアクターにユースケースが提供されないこと

Page 13: PyCon APAC 2013 Web Secure Coding

情報?対象?流通?• 概念データモデリングの段階である程度明らかになっているはず

• システムの外側に何をみせるか?

• プログラムは何を永続化するか?• 平文のパスワードとか• クレジットカードのセキュリティコードとか

Page 14: PyCon APAC 2013 Web Secure Coding

実装に依存するセキュリティ要件

• 攻撃手法が刻々編み出される

• 既知の攻撃方法について対処されている、ということしか証明できない

http://www.flickr.com/photos/danorth1/315489224/

Page 15: PyCon APAC 2013 Web Secure Coding

脆弱性は時系列上で固定ではない

Page 16: PyCon APAC 2013 Web Secure Coding

堅固?• 現時点で既知の脆弱性が存在しない、ではセキュアコーディング足り得ない

• 脆弱性のあるコードが存在しないことが自明な状態であることが、容易に測定出来ること

• 考えたら負け

Page 17: PyCon APAC 2013 Web Secure Coding

考えたら負けDon’t Think...Feel!

Page 18: PyCon APAC 2013 Web Secure Coding

考えたら負け

• 脆弱性有無の計測は何度も行われることになる

• その都度、考えなければ脆弱性有無を判定できないものは「堅固」ではない

Page 19: PyCon APAC 2013 Web Secure Coding

安全性を型に嵌めるいちいち考えないために

Page 20: PyCon APAC 2013 Web Secure Coding

このコードはセキュアですか?

https://gist.github.com/gjo/6473557

Page 21: PyCon APAC 2013 Web Secure Coding

--- is_this_safe.py 2013-09-14 17:42:19.000000000 +0900+++ is_this_safe2.py 2013-09-13 21:07:16.000000000 +0900@@ -40,8 +40,12 @@ sql = 'SELECT {} FROM page'.format(','.join(COLUMNS)) params = [] if None not in (field, value):+ if field not in COLUMNS:+ raise NotFound(field) sql += ' WHERE {} LIKE ?'.format(field)- params.append(value)+ params.append('%{}%'.format(+ value.replace(r'\', r'\\).replace(r'%', r'\%').replace(r'_', r'\_'))+ ) cursor = db.cursor() cursor.execute(sql, params) pages = [dict(zip(COLUMNS, row)) for row in cursor]@@ -62,7 +66,7 @@ <tr><td>No maches. {% endfor %} </table>-""")+""", autoescape=True) return template.render(context)

if __name__ == '__main__':- app.run(debug=True)+ app.run()

Page 22: PyCon APAC 2013 Web Secure Coding

プログラム内部に起因する脆弱性

• メモリ管理、ランタイム関係• バッファオーバーフロー• 不正なシステム特権取得など

• 自爆• デバッグモード、メンテナンスモード• エラーメッセージ

Page 23: PyCon APAC 2013 Web Secure Coding

プログラムの外部インタフェースに起因する脆弱性

• HTTP Request, HTTP Response

• Database

• MessageQueue, Cache, SMTP

• ...etc

Page 24: PyCon APAC 2013 Web Secure Coding

古式ゆかしき何とやら

• SQL Injection

• Directory TraversalOS Command Injection

• Response Header InjectionResponse Header SplitingE-mail Header Injection

Page 25: PyCon APAC 2013 Web Secure Coding

SQL Injection

def some_view(req): sql = 'SELECT * FROM {}'.format( req.GET['some_param'], ) cursor = req.db.cursor() cursor.execute(sql) for row in cursor: some_action(row)

Page 26: PyCon APAC 2013 Web Secure Coding

Directory Traversal

def some_view(req, filename): path = os.path.join(ROOT, filename) content = open(path).read() resp = Response( content=content, content_type='', ) return resp

Page 27: PyCon APAC 2013 Web Secure Coding

OS Command Injection

def some_view(req, cmdopt): resp = Response(content_type='') subprocess.call( 'some_command ' + cmdopt, shell=True, stdout=resp, stderr=subprocess.STDOUT, ) return resp

Page 28: PyCon APAC 2013 Web Secure Coding

Response Header InjectionResponse Header Spliting

HTTP/1.0 200 OKContent-Type: text/htmlDate: Sun, 15 Sep 2013 04:00:00 GMTSet-Cookie: HOGEHOGE; expires=Sun, 15-Jul-2013 15:00:00 GMTConnection: Close

<html>...</html>

Page 29: PyCon APAC 2013 Web Secure Coding

E-Mail Header Injection

Date: Sun, 15 Sep 2013 04:00:00 GMTFrom: "FOO" <[email protected]>To: "BAR" <[email protected]>Subject: Hello BAR: Thank you for your registration

Hi all,foobarbaz.

Page 30: PyCon APAC 2013 Web Secure Coding

共通する危険性• テキストベースのプロトコル• 構造が存在する

• 構造を実現するためにメタキャラクタが存在する

• メタキャラクタを使用することで、誤動作を誘発する

Page 31: PyCon APAC 2013 Web Secure Coding

解法

• 入力のバリデーション

• 出力のエスケープ

Page 32: PyCon APAC 2013 Web Secure Coding

入力のバリデーション• "すべての"入力を検査すべき

• QueryString, FormDataはライブラリが充実している

• それゆえPATH_INFOを忘れがち

• Cookie他ヘッダーも忘れがち

Page 33: PyCon APAC 2013 Web Secure Coding

出力のエスケープ• 出力先毎に異なるエスケープルール

• HTTPレスポンス

• ヘッダー: Cookie, Content-Type, Location etc...

• 本文: HTML, JSON/JSONP, CSV, etc...

• インタフェース

• 永続化等: データベース, ファイルシステム, キャッシュ

• 外部接続: SMTP, Web-API Request, etc...

Page 34: PyCon APAC 2013 Web Secure Coding

なぜ両方必要か?

AppINPUT OUTPUTValidate Escape

入力をAppで使用できる形式に(Byte strem to Python type)

OUTPUTをプロトコルに合わせる(Python type to Byte strem)

Page 35: PyCon APAC 2013 Web Secure Coding

つまらない結論を

Page 36: PyCon APAC 2013 Web Secure Coding

フレームワークのルールに従ってコーディングしましょう

Page 37: PyCon APAC 2013 Web Secure Coding

なぜ?

• ひとつの問題を解決する手法はひとつであるべき

• 同じことを何度も書かない

Page 38: PyCon APAC 2013 Web Secure Coding

どこかで見たような

•Zen of Python

•DRY原則

Page 39: PyCon APAC 2013 Web Secure Coding

チュートリアルの罠

• https://gist.github.com/gjo/6558690

• https://gist.github.com/gjo/6558691

Page 40: PyCon APAC 2013 Web Secure Coding

# -*- coding: utf-8 -*-# http://flask.pocoo.org/docs/quickstart/#a-minimal-application# から# http://flask.pocoo.org/docs/quickstart/#variable-rules# までを写経していくと

from flask import Flask

app = Flask(__name__)

@app.route('/')def index(): return 'Index Page'

@app.route('/hello')def hello(): return 'Hello World'

@app.route('/user/<username>')def show_user_profile(username): # show the user profile for that user return 'User %s' % username

if __name__ == '__main__': app.run()

Page 41: PyCon APAC 2013 Web Secure Coding

# -*- coding: utf-8 -*-# http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/# から抜粋

from wsgiref.simple_server import make_serverfrom pyramid.config import Configuratorfrom pyramid.response import Response

def hello_world(request): return Response('Hello %(name)s!' % request.matchdict)

if __name__ == '__main__': config = Configurator() config.add_route('hello', '/hello/{name}') config.add_view(hello_world, route_name='hello') app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever()

Page 42: PyCon APAC 2013 Web Secure Coding

フレームワークの選択• 必要な外部インタフェースが実装されているか?

• フレームワークへのアドオン追加(新規作成 or グルーコードのみ作成)

• 個別のコードでバリデートやエスケープを実装しない

Page 43: PyCon APAC 2013 Web Secure Coding

では本題

Page 44: PyCon APAC 2013 Web Secure Coding

Against SQL Injection

• SQLを動的に組み立てるなORM使え

• どうしても必要であれば、置換箇所は完全一致で確認して、特殊文字を追い出せ

• Prepared Statementの場合も、値の箇所で評価される特殊文字はハンドルしろ

Page 45: PyCon APAC 2013 Web Secure Coding

SQL LIKE or REGEX

# LIKEのエスケープはORMに任せるquery.filter(MyModel.myfield.endswith( myparam,))

# REGEXのエスケープはまともに書ける# レベルを超えてしまう。。。

Page 46: PyCon APAC 2013 Web Secure Coding

Against Directory Traversal

def safe_path(*args): return os.path.join( [PRE_DEFINED_ROOT] + [os.path.basename(p) for p in args])

def some_view(req, module_, file_): path = safe_path(module_, file_)

Page 47: PyCon APAC 2013 Web Secure Coding

Response Header InjectionResponse Header Spliting

• WSGIサーバーでのResponseHeaderの扱いは単なるByte (!Unicode)

http://www.python.org/dev/peps/pep-3333/#the-start-response-callable

http://www.python.org/dev/peps/pep-3333/#unicode-issues

Page 48: PyCon APAC 2013 Web Secure Coding

• フレームワークごとで動作が違う

• django (convert)https://docs.djangoproject.com/en/1.5/ref/request-response/#setting-headers

• flask (Exception on NL)http://flask.pocoo.org/docs/quickstart/#about-responses

• pyramid (Exception on NL in Key)http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/api/response.html#pyramid.response.Response.headers

Page 49: PyCon APAC 2013 Web Secure Coding

• Cookieはたいてい特別扱いだが、動作そのものは、通常のヘッダの場合とほぼ同じ

• djangohttps://docs.djangoproject.com/en/1.5/ref/request-response/#django.http.HttpResponse.set_cookie

• flaskhttp://flask.pocoo.org/docs/quickstart/#cookies

• pyramidhttp://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/api/response.html#pyramid.response.Response.set_cookie

Page 50: PyCon APAC 2013 Web Secure Coding

E-mail Header Injection

• 標準ライブラリemailでも問題なくエスケープを捌けるhttp://docs.python.jp/2/library/email.header.html#email.header.Header

Page 51: PyCon APAC 2013 Web Secure Coding

(おまけ)

流通しない情報は取得しない

Page 52: PyCon APAC 2013 Web Secure Coding

Script Injection大事なものを忘れていないかい?

Page 53: PyCon APAC 2013 Web Secure Coding

Script Injection

<html>{{ unchecked_var|safe }}</html>

Page 54: PyCon APAC 2013 Web Secure Coding

Script Injection

<script>var x = {{ unchecked }};</script>

Page 55: PyCon APAC 2013 Web Secure Coding

Script Injection

<style>.some-class { color: {{ unchecked }};}</style>

Page 56: PyCon APAC 2013 Web Secure Coding

Script Injection

<script src="{{ unchecked }}"></script>

Page 57: PyCon APAC 2013 Web Secure Coding

スクリプト実行が問題になるのは何故か

• DOMを操作できる

• 新しくHTTP Requestを発生させられる

• iframe, img, link, script

• イベントを発生させられる• a.click, form.submit

Page 58: PyCon APAC 2013 Web Secure Coding

Some Server Attack Servers

Browser

Some Document

Attack Documents

Page 59: PyCon APAC 2013 Web Secure Coding

何が問題か

• 同意していないリクエストが送信される

• パーソナライズされている情報が外部に送信される

Page 60: PyCon APAC 2013 Web Secure Coding

問題が複雑になってしまう背景

• クライアントはサーバーを信用してはならない• クライアントはサーバーを信用せざるを得ない• サーバーはクライアントを信用してはならない• サーバーはクライアントを信用せざるを得ない

Page 61: PyCon APAC 2013 Web Secure Coding

クライアントはサーバーを信用してはならない

• 正しいサーバーに接続しているのか

• サーバーに送信した情報は妥当に取り扱われているのか

• サーバーから受信した情報は信用に足りるのか?

Page 62: PyCon APAC 2013 Web Secure Coding

クライアントはサーバーを信用せざるを得ない

• ひとまず正しいサーバーに接続していると仮定するに足る手法を使う

• ひとまずプライバシーポリシー等のデータハンドリングを信じる

• ひとまずレスポンスは正しいと信じる

Page 63: PyCon APAC 2013 Web Secure Coding

サーバーはクライアントを信用してはならない

• 接続元クライアントが正しいユーザーであるか見分けることは困難

• クライアントから受信した情報が妥当であるか保証できない

• クライアントに送信した情報が適切に扱われるか保証できない

Page 64: PyCon APAC 2013 Web Secure Coding

サーバーはクライアントを信用せざるを得ない

• ひとまず接続元が悪意あるユーザーでないことを証明するに足るチェックを行う

• ひとまずクライアントから受信した入力に虚偽はないと信じるに足るチェックを行う

• ひとまずレスポンスデータが想定しない外部に流出していないことを信じる

Page 65: PyCon APAC 2013 Web Secure Coding

送信してしまったデータの来方行末を保証するものはない• クライアントはサーバーのセキュリティが保たれていることを信じるしかない

• サーバーはクライアントのセキュリティが保たれていることを信じるしかない

Page 66: PyCon APAC 2013 Web Secure Coding

Same Origin PolicyThe Great Wall

Page 67: PyCon APAC 2013 Web Secure Coding

Same Origin Policy

• “scheme://host:port” の組み合わせが一致するものを信じる

• Ajax Requestの範囲を制限する

• (類似の話題: 1st-party Cookie)

Page 68: PyCon APAC 2013 Web Secure Coding

[横道] Cookie

• 適切な範囲のCookieかdomain, path, secure, httpOnly, expire

• (セッション値がhttpOnlyでないのは...)

• 3rd-Party Cookie

• DNT, EU Cookie法

Page 69: PyCon APAC 2013 Web Secure Coding

Browsing Context

• (超省略形) JavaScriptが、どのページで動作するか

• 通常は表示しているページ• script要素で読み込んだ外部Originの

JavaScriptも、表示しているページのContextで動作する

Page 70: PyCon APAC 2013 Web Secure Coding

Browsing Context (Cont.)

• iframe配下のdocumentは別のContext

• Context間でのデータ流通にもSame

Origin Policyが適用される

Page 71: PyCon APAC 2013 Web Secure Coding

本当に信じていいの?• Ajax Requestにしか作用しない

• iframe, img, link, script要素の挿入によるRequestは送信される

• hostsファイル汚染/DNS汚染

• 中間のネットワーク汚染 [New!]

Page 72: PyCon APAC 2013 Web Secure Coding

[横道] Content Security

Policy• HTTP Response Headerで指定

• サーバーが返却するリソースに何を使えるかを厳密に指定できる

• 対応ブラウザーでないと効果なし(Firefox-23, Chrome-25, IE-10 (experimental))

Page 73: PyCon APAC 2013 Web Secure Coding

モダンな何とやら

• XSS (cross site scripting)

• CSRF (cross site request forgery)

• Click-jacking

• Mitigation, BEAST, CRIME, BREACH

Page 74: PyCon APAC 2013 Web Secure Coding

XSS• Script injection等によって攻撃用のJavaScriptをscript

要素で挿入する

• 挿入手段による多くのバリエーション

• HTTP Response Header Spliting

• Response Content-Type誤認バグの利用

• script要素の代わりにimg要素やlink要素を利用

• とにかく意図しないScript実行を抑止するしかない

Page 75: PyCon APAC 2013 Web Secure Coding

CSRF

• 直接POST Requestを送りつける

• 通常はXSSとの併用で踏み台ページを経由する

• すべてのFormにtokenパラメータを付与し、同時にCookieやSessionでもtokenを保持してPOST

受付時に、外部から割り込んだPOSTを抑止する

Page 76: PyCon APAC 2013 Web Secure Coding

Click-jacking

• iframe等を利用して攻撃対象ページを操作する

• 通常はSame Origin Policyによって別ContextのDocumentは操作できない

• 攻撃対象ページにXSS脆弱性があると、踏み台ページのSameOriginでiframeが作成されやりたい放題に

Page 77: PyCon APAC 2013 Web Secure Coding

BEAST, CRIME, BREACH

• SSL保護下にあるデータを総当り的な計算を使用して盗む

• ルーター等でのパケット観測が必要(カンファレンスの無線LANとか)

• 総当り的計算を行うためのRequestをXSSに生成する

Page 78: PyCon APAC 2013 Web Secure Coding

モダンな何とやら (再訪)

• モダンな攻撃の多くはXSSとの組み合わせ

• HTTP Response以外のインタフェースへのエスケープは多くの場合対処済み

• HTTP Response以外では攻撃するためのシーケンスが長くなりがち

• 今更SQL injectionとか恥ずかしいだけ

Page 79: PyCon APAC 2013 Web Secure Coding

まとめ• 日々新しい攻撃方法を考えている人がいます

• 多くは既知の攻撃方法の巧妙な組み合わせにエッセンスを加えたものです

• セキュアであるということは、時系列におけるスナップショットです

• よって何度も確認するハメになります

Page 80: PyCon APAC 2013 Web Secure Coding

間違えようのないやり方がひとつだけあるのがいいね

― Zen of Python

Page 81: PyCon APAC 2013 Web Secure Coding

EOF