5.2K Views
September 23, 24
スライド概要
「OWASP Kansai DAY 2024.09 〜10周年記念セキュリティ・マシマシ全部盛り〜」で使用した資料です。
GraphQLを使ったWebアプリを 攻めの視点から覗いてみる 2024/9/21 OWASP Kansai Adachi Tomohiro
• 本資料は攻撃を推奨するものではなく、攻撃側の視点からできる ことを⾒ることで、防御に必要な知識を得ていただくことを⽬的 に作成しています。 • ⾃⾝の管理外の環境に対して本資料内の⼿法を実⾏した場合、法 律で罰せられる可能性がありますので、絶対に実⾏しないでくだ さい。 • 前述の⾏為等により発⽣する問題・責任について、著作者は⼀切 の責任を負いません。 2
⾃⼰紹介 名前︓ Adachi Tomohiro(@att0att0) 所属︓ GMOサイバーセキュリティ by イエラエ株式会社 OWASP Kansaiボードメンバー 主にWebアプリの脆弱性診断をしています 3
GraphQLとは • API⽤のクエリ⾔語 • 必要なデータを指 定して取得するこ とが可能なので、 効率的なデータ取 得ができる 参考・引⽤︓https://graphql.org/ 4
GraphQLとは このハンズオンの中では以下を取り扱います。 (Subscriptionは出てきません) ■Query 主にデータ取得で⽤いる ■ Mutation 主にデータの作成・更新・削除で⽤いる 5
クエリの⾒⽅ Queryなら「query」 Queryの場合は省略可 Mutationなら「mutation」 6
クエリの⾒⽅ オペレーション名 実⾏するクエリの識別につけ る名前 リクエストで使⽤しない場合 は省略可 7
クエリの⾒⽅ Query / Mutation型に属す るフィールド名 8
クエリの⾒⽅ 「thread」というオブジェ クト型のフィールドに属する フィールド名 9
クエリの⾒⽅ レスポンスでは、実⾏したクエリ で指定したフィールド(id,title) のデータが返される 10
クエリの⾒⽅ 引数として、動的パラ メータを渡すことも可能 11
クエリの⾒⽅ クエリ内にハードコードせず、 外部から「variables」という パラメータを介して渡すことも 可能 12
クエリの⾒⽅ フィールドを追加することで、取得するデータが増える 13
クエリの⾒⽅ 何でもフィールドが追加できるわけではない 14
GraphQLとは 指定できるフィールドって何で分かる︖ 15
Introspection イントロスペクションクエリを 実⾏することで、APIで定義さ れたスキーマ情報を取得可能 スキーマ情報から、実⾏可能な Query・Mutationや指定でき るフィールド・引数の情報が分 かる 16
Introspectionの結果例 17
Introspectionの結果例 18
実際に触ってみる① Burp Suiteの「Open browser」より起動したブラウザから、 デモサイトにアクセス 19
実際に触ってみる① Burpの「proxy」タブの 「HTTP history」を選択 表⽰されたログから、 TOPページにアクセスし た際のリクエスト(query thread)を選択 20
実際に触ってみる① ⾚枠内で右クリック→ 「Send to Repeater」を クリック 21
実際に触ってみる① 「Repeater」タブのリクエ スト部分で右クリック→ 「GraphQL」→ 「Set introspection query」 をクリック 22
実際に触ってみる① イントロスペクションクエリ が反映されていることを確認 し、「Send」をクリックして リクエストを送信 23
実際に触ってみる① レスポンスでスキーマの情報が返される 24
実際に触ってみる① ] Query型に属するフィールド「thread」があり 「Thread」という名前のオブジェクト型のデータを返す 25
実際に触ってみる① 「Thread」という名前のオブジェクト型のフィールドに属する、 26 「id」「title」フィールドがあることが確認できる
とはいえレスポンスのJSONから 辿っていくのはちょとしんどい 27
GraphQL Voyager SDL形式のスキーマ情報 や、イントロスペクショ ンの結果(JSON)を使⽤ し、スキーマ情報を視覚 化してくれるツールの1つ https://github.com/graphql-kit/graphql-voyager 28
実際に触ってみる② 「CHANGE SCHEMA」 をクリック後、 「INTROSPECTION」 を選択 29
実際に触ってみる② イントロスペクション 実⾏時のレスポンスの JSONをコピー 30
実際に触ってみる② 「INTROSPECTION」 にペースト後、「DISP LAY」をクリック 31
実際に触ってみる② Queryのスキーマ情報 32
実際に触ってみる② Mutationのスキーマ情報 33
スキーマの情報の⾒⽅ 例えばQueryであれば、 この2つがQuery型に属 するフィールドである ことが分かる フィールド名 返すデータの型 (!はnullを許容しない) 34
スキーマの情報の⾒⽅ スキーマ情報からクエリを組むことができる 35
Introspectionでスキーマ情報が取得できると 実⾏できるQueryやMutation等の情報が分かる 36
GraphQLとは スキーマ情報なんてなくても アプリ操作すればそれで分かるのでは︖ 37
TOP画⾯アクセス時 38
投稿時 39
ログイン時 40
新規登録時 41
Queryの場合 Queryの場合、「flag」は先ほどの画⾯操作で確認できていない 42
Mutationの場合 Mutationでは、「loginotp」が先ほどの画⾯操作で確認できていない 43
実際に触ってみる③ 「query flag」を実⾏するために 「support」フォルダ内の「query_flag.txt」の内容をコピー 44
実際に触ってみる③ 「/graphql」へのリクエ ストのログを選択後、 ⾚枠内で右クリック→ 「Send to Repeater」を クリック 45
実際に触ってみる③ Repeaterに送信したリクエストのリクエストボディを 先ほどコピーした内容に置換 46
実際に触ってみる③ この時に実⾏されるクエリの 内容は、「GraphQL」タブ から確認できる 「Send」をクリックしてリ クエストをAPIへ直接送信 47
実際に触ってみる③ 未認証での実⾏はエラーになる ことが確認できたので、次は認 証状態で実⾏してみる 48
実際に触ってみる③ 以下の認証情報 or 「Signup」 からアカウント登録をしてログ イン email︓[email protected] PW :password 49
実際に触ってみる③ 「HTTP history」のロ グから、レスポンスで 返されたアクセストー クンをコピー 50
実際に触ってみる③ 「authorization: Bearer null」のnullの部分に、コピーしたトーク 51 ンをペースト「Send」でリクエスト送信
実際に触ってみる③ レスポンスの内容から、 管理者で実⾏する必要が あることが分かった 52
スキーマの情報を⾒ながら 何か⽅法がないか探してみる 53
実際に触ってみる④ 表⽰をMutationに切り替 えた後、左のメニューの 「Mutation」をクリック 54
実際に触ってみる④ Mutation時に渡せる引数の情報 が⾒える 55
実際に触ってみる④ 各Mutationを選択すると、引数 の型情報も確認できる 56
実際に触ってみる④ 「registerUser」を⾒ると気に なる部分がある 57
実際に触ってみる④ 「adminflg」という、いかにも な引数が定義されている 58
実際に触ってみる④ 画⾯操作時のMutationでは送信されていなかった引数 59
実際に触ってみる④ 引数を追加した「mutation registerUser」を実⾏するために 「support」フォルダ内の「mutation_registerUser.txt」の内容をコピー 60
実際に触ってみる④ 「/graphql」へのリクエ ストのログを選択後、 ⾚枠内で右クリック→ 「Send to Repeater」を クリック 61
実際に触ってみる④ Repeaterに送信したリクエストのリクエストボディを 先ほどコピーした内容に置換 62
実際に触ってみる④ この時に実⾏されるクエリの 内容は、「GraphQL」タブ から確認できる 「Send」をクリックしてリ クエストをAPIへ直接送信 63
実際に触ってみる④ 先ほど登録したアカウント でログイン email︓[email protected] PW︓1qazxsw2 64
実際に触ってみる④ 通常のアカウントのログイ ンでは表⽰されなかった、 2段階認証の画⾯が表⽰さ れた 65
実際に触ってみる④ 正しいコード以外はエラー になる 66
コードの総当たり コードを「0001」〜「9999」まで総当たりしてみる 67
コードの総当たり 短い間隔で多数のリクエストを送信するとレート制限がかかる 68 かつ、コードの有効期限内(3分)の制限がある
コードの総当たり リクエストを⼤量に送信する⽅法では難しい 69
GraphQLとは 今回のデモアプリの場合、 限られた時間内に 限られたリクエスト数で総当たりができること が条件になる 70
GraphQLのエイリアス 引数の値が異なる同名フィールドを追加して、1度のリクエスト で複数の処理を実⾏してみる 71
GraphQLのエイリアス フィールド名「loginopt」で返すデータが「0001」と「0002」 の時の異なる結果があるので、コンフリクトしている 72
GraphQLのエイリアス エイリアスを使⽤し、フィールドに別名をつけることで、コンフ リクトを回避することができる 73
GraphQLのエイリアス エイリアスで増やした分だけ、引数の値が異なる同じ処理を、1 つのリクエストで複数実⾏することが可能になる 74
実際に触ってみる⑤ エイリアスを使⽤した「mutation loginotp」を実⾏するために 「support」フォルダ内の「mutation_loginotp.txt」の内容をコピー 75
実際に触ってみる⑤ email︓[email protected] PW ︓1qazxsw2 3分間の制限があるので、再度作成したadmin権限のアカウント でログインして、任意の認証コードを送信 76
実際に触ってみる⑤ 「mutation loginotp」の ログを選択後、 ⾚枠内で右クリック→ 「Send to Repeater」を クリック 77
実際に触ってみる⑤ 「GraphQL」タブのmutationの内容を、先ほどコピーした内容 に置換後、「Send」でリクエストを送信 78
実際に触ってみる⑤ レスポンスで返されるデータの中に、アクセストークンが含まれ 79 ていることを確認
実際に触ってみる⑤ 最初に実⾏した「query flag」のリクエストの、アクセストーク ン部分を先ほど取得した値に置換後「Send」でリクエスト送信 80
実際に触ってみる⑤ 管理者権限で実⾏したこ とで、データの取得がで きたことを確認 81
デモアプリでできたこと 通常の画⾯操作では登録できない、管理者権限のユーザを作成す ることができた 2段階認証の仕組みを回避することができた 通常の画⾯操作では実⾏されず、かつ管理者権限のユーザのみが 実⾏可能なqueryを実⾏し、データ取得ができた 82
GraphQLとは 何がダメだったかを考えてみる 83
きっかけ Introspectionが有効化されていて、利⽤者がスキーマ情報を取得できた 84
その結果できたこと 通常の画⾯操作では実⾏されないqueryの存在が確認できた 85
その結果できたこと 通常の画⾯操作では送信されない引数の存在が確認できた 86
他にも実は 「query thread」では「secretmemo」や「author」フィールドから 「email」「admin」フィールドを指定することができた 87
他にも実は TOP画⾯アクセス時に実⾏されるqueryの内容と、取得したデータ 88
他にも実は ※Joeアカウント・・・ID・PWが同じアカウント フィールドを追加することで、通常の画⾯操作では取得できない 情報が取得できた 89
GraphQLとは Introspectionを無効化しておく 90
Field suggestion 誤ったフィールド名を指定した際に、親切にフィールド名のサ ジェストをしてくれる場合は、そこから存在するフィールド名 の特定につながる可能性がある 91
GraphQLとは Field suggestionも無効化しておく 92
GraphQLとは 攻撃に繋げられるような情報を 簡単に与えない 93
GraphQLとは スキーマで定義された情報が隠されていても 定義されたquery・mutationの実⾏や フィールド・引数の追加が 禁⽌されるわけではない 94
GraphQLとは スキーマで定義したquery・mutation フィールドや引数等の情報は 全てアクセス・利⽤される 可能性があることを前提に考える 95
GraphQLとは フィールド追加によって、 ⾒えると困る情報の取得が可能ではないか︖ 96
デモアプリでの例 NGなら認可制御を⾏う・不要なら実装からフィールドを取り除くなど 97
GraphQLとは 引数の追加によって、 本来はアプリ操作ではできると困るような 処理が⾏えてしまわないか︖ 98
デモアプリでの例 不要なら実装から引数を取り除く 99
DoSに繋がるクエリ ⼤量のエイリアス フィールドの循環参照 100
⼀例として・・・ GraphQLとは リクエストの中で実⾏するエイリアス数を制限 101
⼀例として・・・ GraphQLとは 循環参照を⾏わないスキーマ設計を⾏う 難しい場合はクエリのネストの深さを制限する 102
GraphQLとは クエリのコスト計算による対策 103
GraphQLとは あらかじめ決まったクエリのみ実⾏を許す 「Persisted Query」というものも存在する 104
まとめ • 攻撃に繋げられるような情報を簡単に与えない • Introspectionを無効化する • Field suggestionを無効化する • アプリ操作で実⾏されるクエリ以外にも、スキーマで定義され ているフィールドや引数等を追加することで、通常のアプリ操 作では取得しない情報の取得や、処理の実⾏につながる可能性 がある • スキーマで定義したフィールドや引数等の情報は、全てアクセスされ る可能性があることを前提に、対象のデータが返されても問題ないか、 困るような処理が⾏われないかを確認する • NGなら認可制御を⾏う、不要なら実装からそのフィールド・引数を取 り除くなど 105
まとめ • 攻撃に繋げられるような情報を簡単に与えない • Introspectionを無効化する • Field suggestionを無効化する 106
まとめ • アプリ操作で実⾏されるクエリ以外にも、スキーマで定義され ているフィールドや引数等を追加することで、通常のアプリ操 作では取得しない情報の取得や、処理の実⾏につながる可能性 がある • スキーマで定義したフィールドや引数等の情報は、全てアクセスされ る可能性があることを前提に、対象のデータが返されても問題ないか、 困るような処理が⾏われないかを確認する • NGなら認可制御を⾏う、不要なら実装からそのフィールド・引数を取 り除くなど 107
ああ ご参加 ご清聴ありがとうございました︕ 108