SlideShare a Scribd company logo
Webセキュア
コーディングの基本
on 2013-09-15 13:00-13:50JST
at PyCON APAC 2013 Room A0765 (Ja2)
by OCHIAI, Gouji (@gjo)
Abstract
• セキュアコーディングとは何か?
• Webシステムにおけるセキュリティ
• コード解説中心
• 基本的な内容しかやりません
• 「お前が言うな」は重々承知
お前誰よ?
• 落合 豪史
@gjo
• 一応職業プログラマー
セキュリティの専門家
とかではないです
• twitter.com/gjo
github.com/gjo
本セッションおよび本稿の内
容は私個人の見解であり、私
の所属する企業、団体等とは
一切の関わりはありません。
TheYear of Python
Year of the Dragon
心を入れ替えるよ
その方法を教えてくれ
セキュアコーディングとは
何か?
• 脆弱性に対して堅固な
コーディング
• 脆弱性?
• 堅固?
http://www.flickr.com/photos/nene9/4444657449/
セキュアな状態?
• 一般的にセキュリティ
は非機能要件
• 「セキュリティが保た
れていること」
• 実装に依存する要件
• 実装に依存しない要件
http://www.flickr.com/photos/jermainejustice/3352100979/
実装に依存しない
セキュリティ要件
• 「必要でない情報」を
• 「必要でない対象」に
• 「流通しない」
実装に依存しない
セキュリティ要件 (Cont.)
• 「必要な情報」を
• 「必要な対象」に
• 「流通する」
• 一般的な機能要件の逆
相互作用を持たないアクターに
ユースケースが提供されないこと
情報?対象?流通?
• 概念データモデリングの段階である程度明らかに
なっているはず
• システムの外側に何をみせるか?
• プログラムは何を永続化するか?
• 平文のパスワードとか
• クレジットカードのセキュリティコードとか
実装に依存する
セキュリティ要件
• 攻撃手法が刻々編み出
される
• 既知の攻撃方法につい
て対処されている、と
いうことしか証明でき
ない
http://www.flickr.com/photos/danorth1/315489224/
脆弱性は時系列上で
固定ではない
堅固?
• 現時点で既知の脆弱性が存在しない、
ではセキュアコーディング足り得ない
• 脆弱性のあるコードが存在しないこと
が自明な状態であることが、容易に測
定出来ること
• 考えたら負け
考えたら負け
Don’t Think...Feel!
考えたら負け
• 脆弱性有無の計測は何度も行われるこ
とになる
• その都度、考えなければ脆弱性有無を
判定できないものは「堅固」ではない
安全性を型に嵌める
いちいち考えないために
このコードは
セキュアですか?
https://gist.github.com/gjo/6473557
--- is_this_safe.py2013-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()
プログラム内部に
起因する脆弱性
• メモリ管理、ランタイム関係
• バッファオーバーフロー
• 不正なシステム特権取得など
• 自爆
• デバッグモード、メンテナンスモード
• エラーメッセージ
プログラムの外部
インタフェースに起因する脆弱性
• HTTP Request, HTTP Response
• Database
• MessageQueue, Cache, SMTP
• ...etc
古式ゆかしき何とやら
• SQL Injection
• Directory Traversal
OS Command Injection
• Response Header Injection
Response Header Spliting
E-mail Header Injection
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)
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
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
Response Header Injection
Response Header Spliting
HTTP/1.0 200 OK
Content-Type: text/html
Date: Sun, 15 Sep 2013 04:00:00 GMT
Set-Cookie: HOGEHOGE; expires=Sun, 15-Jul-2013 15:00:00 GMT
Connection: Close
<html>
...
</html>
E-Mail Header Injection
Date: Sun, 15 Sep 2013 04:00:00 GMT
From: "FOO" <foo@example.org>
To: "BAR" <bar@example.org>
Subject: Hello BAR: Thank you for your registration
Hi all,
foo
bar
baz
.
共通する危険性
• テキストベースのプロトコル
• 構造が存在する
• 構造を実現するためにメタキャラクタが
存在する
• メタキャラクタを使用することで、
誤動作を誘発する
解法
• 入力のバリデーション
• 出力のエスケープ
入力のバリデーション
• "すべての"入力を検査すべき
• QueryString, FormDataはライブラリが
充実している
• それゆえPATH_INFOを忘れがち
• Cookie他ヘッダーも忘れがち
出力のエスケープ
• 出力先毎に異なるエスケープルール
• HTTPレスポンス
• ヘッダー: Cookie, Content-Type, Location etc...
• 本文: HTML, JSON/JSONP, CSV, etc...
• インタフェース
• 永続化等: データベース, ファイルシステム, キャッシュ
• 外部接続: SMTP,Web-API Request, etc...
なぜ両方必要か?
AppINPUT OUTPUTValidate Escape
入力をAppで使用できる形式に
(Byte strem to Python type)
OUTPUTをプロトコルに合わせる
(Python type to Byte strem)
つまらない結論を
フレームワークの
ルールに従って
コーディング
しましょう
なぜ?
• ひとつの問題を解決する手法は
ひとつであるべき
• 同じことを何度も書かない
どこかで見たような
•Zen of Python
•DRY原則
チュートリアルの罠
• https://gist.github.com/gjo/6558690
• https://gist.github.com/gjo/6558691
# -*- 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()
# -*- coding: utf-8 -*-
# http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/
# から抜粋
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from 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()
フレームワークの選択
• 必要な外部インタフェースが実装され
ているか?
• フレームワークへのアドオン追加
(新規作成 or グルーコードのみ作成)
• 個別のコードでバリデートやエスケー
プを実装しない
では本題
Against SQL Injection
• SQLを動的に組み立てるな
ORM使え
• どうしても必要であれば、置換箇所は完
全一致で確認して、特殊文字を追い出せ
• Prepared Statementの場合も、値の箇所
で評価される特殊文字はハンドルしろ
SQL LIKE or REGEX
# LIKEのエスケープはORMに任せる
query.filter(MyModel.myfield.endswith(
myparam,
))
# REGEXのエスケープはまともに書ける
# レベルを超えてしまう。。。
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_)
Response Header Injection
Response 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
• フレームワークごとで動作が違う
• 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
• Cookieはたいてい特別扱いだが、動作そ
のものは、通常のヘッダの場合とほぼ同
じ
• django
https://docs.djangoproject.com/en/1.5/ref/request-response/#django.http.HttpResponse.set_cookie
• flask
http://flask.pocoo.org/docs/quickstart/#cookies
• pyramid
http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/api/
response.html#pyramid.response.Response.set_cookie
E-mail Header Injection
• 標準ライブラリemailでも問題なくエス
ケープを捌ける
http://docs.python.jp/2/library/email.header.html#email.header.Header
(おまけ)
流通しない情報は
取得しない
Script Injection
大事なものを忘れていないかい?
Script Injection
<html>
{{ unchecked_var|safe }}
</html>
Script Injection
<script>
var x = {{ unchecked }};
</script>
Script Injection
<style>
.some-class {
color: {{ unchecked }};
}
</style>
Script Injection
<script
src="{{ unchecked }}">
</script>
スクリプト実行が問題にな
るのは何故か
• DOMを操作できる
• 新しくHTTP Requestを発生させられる
• iframe, img, link, script
• イベントを発生させられる
• a.click, form.submit
Some Server Attack Servers
Browser
Some
Document
Attack
Documents
何が問題か
• 同意していないリクエストが送信され
る
• パーソナライズされている情報が外部
に送信される
問題が複雑になってしまう
背景
• クライアントはサーバーを信用してはならない
• クライアントはサーバーを信用せざるを得ない
• サーバーはクライアントを信用してはならない
• サーバーはクライアントを信用せざるを得ない
クライアントはサーバーを
信用してはならない
• 正しいサーバーに接続しているのか
• サーバーに送信した情報は妥当に取り
扱われているのか
• サーバーから受信した情報は信用に足
りるのか?
クライアントはサーバーを
信用せざるを得ない
• ひとまず正しいサーバーに接続してい
ると仮定するに足る手法を使う
• ひとまずプライバシーポリシー等のデ
ータハンドリングを信じる
• ひとまずレスポンスは正しいと信じる
サーバーはクライアントを
信用してはならない
• 接続元クライアントが正しいユーザー
であるか見分けることは困難
• クライアントから受信した情報が妥当
であるか保証できない
• クライアントに送信した情報が適切に
扱われるか保証できない
サーバーはクライアントを
信用せざるを得ない
• ひとまず接続元が悪意あるユーザーでない
ことを証明するに足るチェックを行う
• ひとまずクライアントから受信した入力に
虚偽はないと信じるに足るチェックを行う
• ひとまずレスポンスデータが想定しない外
部に流出していないことを信じる
送信してしまったデータの来
方行末を保証するものはない
• クライアントはサーバーのセキュリテ
ィが保たれていることを信じるしかな
い
• サーバーはクライアントのセキュリテ
ィが保たれていることを信じるしかな
い
Same Origin Policy
The Great Wall
Same Origin Policy
• “scheme://host:port” の組み合わせが一致
するものを信じる
• Ajax Requestの範囲を制限する
• (類似の話題: 1st-party Cookie)
[横道] Cookie
• 適切な範囲のCookieか
domain, path, secure, httpOnly, expire
• (セッション値がhttpOnlyでないのは...)
• 3rd-Party Cookie
• DNT, EU Cookie法
Browsing Context
• (超省略形) JavaScriptが、どのページで動
作するか
• 通常は表示しているページ
• script要素で読み込んだ外部Originの
JavaScriptも、表示しているページの
Contextで動作する
Browsing Context
(Cont.)
• iframe配下のdocumentは別のContext
• Context間でのデータ流通にもSame
Origin Policyが適用される
本当に信じていいの?
• Ajax Requestにしか作用しない
• iframe, img, link, script要素の挿入による
Requestは送信される
• hostsファイル汚染/DNS汚染
• 中間のネットワーク汚染 [New!]
[横道] Content Security
Policy
• HTTP Response Headerで指定
• サーバーが返却するリソースに何を使
えるかを厳密に指定できる
• 対応ブラウザーでないと効果なし
(Firefox-23, Chrome-25, IE-10
(experimental))
モダンな何とやら
• XSS (cross site scripting)
• CSRF (cross site request forgery)
• Click-jacking
• Mitigation, BEAST, CRIME, BREACH
XSS
• Script injection等によって攻撃用のJavaScriptをscript
要素で挿入する
• 挿入手段による多くのバリエーション
• HTTP Response Header Spliting
• Response Content-Type誤認バグの利用
• script要素の代わりにimg要素やlink要素を利用
• とにかく意図しないScript実行を抑止するしかない
CSRF
• 直接POST Requestを送りつける
• 通常はXSSとの併用で踏み台ページを経由する
• すべてのFormにtokenパラメータを付与し、同
時にCookieやSessionでもtokenを保持してPOST
受付時に、外部から割り込んだPOSTを抑止す
る
Click-jacking
• iframe等を利用して攻撃対象ページを操作する
• 通常はSame Origin Policyによって別Contextの
Documentは操作できない
• 攻撃対象ページにXSS脆弱性があると、踏み台
ページのSameOriginでiframeが作成されやりた
い放題に
BEAST, CRIME, BREACH
• SSL保護下にあるデータを総当り的な計
算を使用して盗む
• ルーター等でのパケット観測が必要
(カンファレンスの無線LANとか)
• 総当り的計算を行うためのRequestを
XSSに生成する
モダンな何とやら (再訪)
• モダンな攻撃の多くはXSSとの組み合わせ
• HTTP Response以外のインタフェースへ
のエスケープは多くの場合対処済み
• HTTP Response以外では攻撃するための
シーケンスが長くなりがち
• 今更SQL injectionとか恥ずかしいだけ
まとめ
• 日々新しい攻撃方法を考えている人がいます
• 多くは既知の攻撃方法の巧妙な組み合わせ
にエッセンスを加えたものです
• セキュアであるということは、時系列にお
けるスナップショットです
• よって何度も確認するハメになります
間違えようのないやり方が
ひとつだけあるのがいいね
― Zen of Python
EOF

More Related Content

PDF
マークアップ講座 01b HTML
PPT
ザ・ドキュメント~うまくいかないNoSQL~
PDF
Html5でword pressテーマを作るよ!
PDF
MongoDBのはじめての運用テキスト
PPTX
Chunked encoding を使った高速化の考察
PPTX
メタな感じのプログラミング(プロ生 + わんくま 071118)
PDF
MongoDB very basic (Japanese) / MongoDB基礎の基礎
PDF
GrailsでSpringをGroovyにしよう!
マークアップ講座 01b HTML
ザ・ドキュメント~うまくいかないNoSQL~
Html5でword pressテーマを作るよ!
MongoDBのはじめての運用テキスト
Chunked encoding を使った高速化の考察
メタな感じのプログラミング(プロ生 + わんくま 071118)
MongoDB very basic (Japanese) / MongoDB基礎の基礎
GrailsでSpringをGroovyにしよう!

What's hot (20)

PDF
MongoDBざっくり解説
PPTX
JJUG CCC 2011 Fall / Web test automation with Geb and Spock
PDF
O/Rマッパーによるトラブルを未然に防ぐ
PDF
Djangoフレームワークの紹介
PDF
MongoDB Configパラメータ解説
PDF
Djangoフレームワークの紹介
PPT
第5回勉強会
PDF
OAuth 2.0 Web Messaging Response Mode - OpenID Summit Tokyo 2015
PDF
MongoDBのアレをアレする
PDF
Djangoエンジニアの観点から見たHue
PDF
ゲーム開発プロセスカイゼン
PDF
後悔しないもんごもんごの使い方 〜アプリ編〜
PDF
Djangoフレームワークのユーザーモデルと認証
PPTX
PHP基礎勉強会
PDF
What's new! TwentyThirteen + WordPress3.6
PDF
20150131_jQueryのようにWebテストが書けるGeb Navigator APIの紹介
PDF
HTTP入門
PDF
映画にでてくるハッカーになりたい - YAPC Asia 2010
PDF
Phpstudy44 Zend Frameworkが抱えている問題は多い。
PDF
Zabbix API
MongoDBざっくり解説
JJUG CCC 2011 Fall / Web test automation with Geb and Spock
O/Rマッパーによるトラブルを未然に防ぐ
Djangoフレームワークの紹介
MongoDB Configパラメータ解説
Djangoフレームワークの紹介
第5回勉強会
OAuth 2.0 Web Messaging Response Mode - OpenID Summit Tokyo 2015
MongoDBのアレをアレする
Djangoエンジニアの観点から見たHue
ゲーム開発プロセスカイゼン
後悔しないもんごもんごの使い方 〜アプリ編〜
Djangoフレームワークのユーザーモデルと認証
PHP基礎勉強会
What's new! TwentyThirteen + WordPress3.6
20150131_jQueryのようにWebテストが書けるGeb Navigator APIの紹介
HTTP入門
映画にでてくるハッカーになりたい - YAPC Asia 2010
Phpstudy44 Zend Frameworkが抱えている問題は多い。
Zabbix API
Ad

Similar to PyCon APAC 2013 Web Secure Coding (20)

PDF
プロセスの永続化でコスト削減 #perlbeginners
PDF
JSDoc ToolKit
PDF
minneで学ぶクラウド脳
PDF
Hatena blogdevelopmentflow
PDF
PythonのGUI_2018 with NSEG
PPTX
Talking about Microsoft On-premises Data Gateway
PDF
PostgreSQLのトラブルシューティング@第5回中国地方DB勉強会
PPTX
Keycloakの実際・翻訳プロジェクト紹介
PDF
インフォグラフィックス時代のD3.js入門
PPTX
Clack meetup #1 lt
PDF
PlaySQLAlchemyORM2017.key
PDF
GDG Women DevfestW
PPTX
開発を彩る技術たち
PDF
すぐ始めれるクラウド
PDF
インフラ運用管理ツールとGolang OSS運用管理勉強会LT
PDF
20140823 LL diver Angular.js で構築した note に関して
PPTX
PHPにないセキュリティ機能
PPTX
PHPにないセキュリティ機能
PDF
Javaで1から10まで書いた話(sanitized)
PDF
RealtimeTweakPickerMode
プロセスの永続化でコスト削減 #perlbeginners
JSDoc ToolKit
minneで学ぶクラウド脳
Hatena blogdevelopmentflow
PythonのGUI_2018 with NSEG
Talking about Microsoft On-premises Data Gateway
PostgreSQLのトラブルシューティング@第5回中国地方DB勉強会
Keycloakの実際・翻訳プロジェクト紹介
インフォグラフィックス時代のD3.js入門
Clack meetup #1 lt
PlaySQLAlchemyORM2017.key
GDG Women DevfestW
開発を彩る技術たち
すぐ始めれるクラウド
インフラ運用管理ツールとGolang OSS運用管理勉強会LT
20140823 LL diver Angular.js で構築した note に関して
PHPにないセキュリティ機能
PHPにないセキュリティ機能
Javaで1から10まで書いた話(sanitized)
RealtimeTweakPickerMode
Ad

PyCon APAC 2013 Web Secure Coding