動的解析の認証と巡回範囲
検査したURLの数だけでなく、認証後の機能へ到達した範囲を確認します。
説明
DASTは動くアプリへ要求を送り、応答や挙動を調べます。ログインできているか、対象の機能へ到達できているかによって、検査できる範囲が変わります。
固定のWSGIアプリをテスト要求で呼び出します。未認証の応答、ログイン、認証後のリンク、API到達を同じ履歴で追い、応答とアプリ内の実行記録を照合します。
検査したURLの数だけでなく、認証後の機能へ到達した範囲を確認します。
1公開入口から得られるリンクを読む
WSGIのテスト要求でアプリを呼びます。
from sp19 import *
lab=App()
status,headers,body=request公開入口から得られるリンクを読む(lab,'/')
print(status,body)公開ページには/loginだけがあります。ここから見えるリンクだけでは/privateや/APIの内容を検査できません。
2認証なしで保護ページへ要求する
/privateを直接指定します。
print(request認証なしで保護ページへ要求する(lab,'/private')[0:1])
print(lab.trace[-1])401 Unauthorizedです。要求は到達していますが、保護された業務処理を実行したことにはなりません。
3固定の試験資格情報でログインする
公開のpublic-trainingという試験文字列を使います。
status,headers,body=request(lab,'/login','POST',b'public-training')
print(status,headers['Set-Cookie固定の試験資格情報でログインする'],body)
cookie=headers['Set-Cookie'].split(';',1)[0]セッションCookieと/privateへのリンクを受け取ります。これは教材用アプリの固定セッションです。
4セッションを付けて保護ページを開く
Cookieを次の要求に引き継ぎます。
print(request(lab,'/private',cookie=cookieセッションを付けて保護ページを開く)[::2])200 OKと/api/exportへのリンクです。認証が必要な経路が新しく見つかりました。
5APIの実処理へ到達する
認証済みの要求で公開2行を取得します。
print(requestAPIの実処理へ到達する(lab,'/api/export',cookie=cookie)[::2])alphaとbetaが返ります。アプリ内でSQLを実行し、その値を応答へ変換した結果です。
6Cookieの欠落で検査範囲が変わることを確認する
同じAPIへCookieなしで要求します。
print(requestCookieの欠落で検査範囲が変わることを確認する(lab,'/api/export')[::2])401とauthenticationエラーです。エラー応答が返るだけの試行を、認証後機能の検査成功に含めません。
7応答とアプリ内の実行記録を照合する
各行はメソッド、パス、応答コード、認証状態です。
for row in lab.trace応答とアプリ内の実行記録を照合する:print(row)
print(sorted({path for method,path,status,auth in lab.trace if auth and status=='200'}))認証済みで200になったのは/privateと/api/exportです。IASTなど実行時の観測と照合する場合も、同じ要求に結び付けて範囲を確認します。
まとめ
認証の成功と対象機能への到達を確認します。
セッションを引き継いだ要求で検査します。
応答と実行時の記録を照合します。
操作履歴と解説を振り返れます。
Python 3.15 / AST・SQLite・WSGIの固定アプリ
from sp19 import *
lab=App()
status,headers,body=request(lab,'/')
print(status,body)200 OK {'links': ['/login']}print(request(lab,'/private')[0:1])
print(lab.trace[-1])('401 Unauthorized',)
('GET', '/private', '401', False)status,headers,body=request(lab,'/login','POST',b'public-training')
print(status,headers['Set-Cookie'],body)
cookie=headers['Set-Cookie'].split(';',1)[0]200 OK sid=public-training-s7; HttpOnly; SameSite=Strict {'links': ['/private']}print(request(lab,'/private',cookie=cookie)[::2])('200 OK', {'links': ['/api/export']})print(request(lab,'/api/export',cookie=cookie)[::2])('200 OK', {'rows': [['alpha'], ['beta']]})print(request(lab,'/api/export')[::2])('401 Unauthorized', {'error': 'authentication'})for row in lab.trace:print(row)
print(sorted({path for method,path,status,auth in lab.trace if auth and status=='200'}))('GET', '/', '200', False)
('GET', '/private', '401', False)
('POST', '/login', '200', False)
('GET', '/private', '200', True)
('GET', '/api/export', '200', True)
('GET', '/api/export', '401', False)
['/api/export', '/private']演習完了