JWTの脆弱な署名と不十分な署名問題に関する理解
JWT(Json Web Token)の批判記事を見ているとたまに出てくるシグネチャを算出する際のアルゴリズムalgの仕様問題についての認識をまとめる。
JWTには改竄検知を行うJWS(Json Web Signature)という形式がある。
JWSのフォーマットは以下である。
base64encode(json header).base64encode(json payload).base64encode(signature)
signatureは以下のフォーマットをheaderのalgパラメータで指定したアルゴリズムで署名したバイナリである。
{json header}.{json payload}
問題はJWSのRFCの仕様とJWSを受け取った側の検証方法による2点が存在する。ちなみにこれはRFC 8725 - 2.1. Weak Signatures and Insufficient Signature Valudationに記載されている。
- algには
none
という値を許容する仕様があり、noneの場合は検証側がヘッダー・ペイロードの改竄を検知できない。 - JWSは暗号化されていないので公開鍵暗号RSAで署名したにも関わらず、改竄後にalgを共通鍵暗号方式SHAに変更されてしまい、改竄後に公開鍵で作成されるシグネチャを結合される。このような状態では公開鍵を用いて作られたシグネチャを共通鍵暗号方式で検証してしまう。
1はシグネチャによる改竄検知が強いだったのにも関わらず、シグネチャを生成しない仕様を許容してしまったことに由来する。
JWTライブラリがこの仕様に則って実装している場合、検証時に改竄検知のできないJWSを受け取れるようになってしまう。noneを受け取らないような実装の場合はRFC違反ということ?
2は以下の通りである。
algにRSAを指定した場合、本来公開鍵鍵で署名されたシグネチャを持つJWSになる。
しかし、JWSは暗号化されていないため、ヘッダー・ペイロードは見ることができ改竄できてしまう。
それを検知するためのシグネチャだったが、ヘッダーのalgを共通鍵方式に変更・ペイロードも改竄して公開鍵で再度シグネチャを生成することが可能。
このような状態では公開鍵を用いて作られたシグネチャを共通鍵暗号方式で検証してしまう。公開鍵は攻撃者も入手でき、それを共通鍵として検証に用いるのでシグネチャの意味がなくなる。
2に関しては鍵のアルゴリズムを取得して、ヘッダーのalgと比較して検知する方法がありそう。
鍵のアルゴリズムがRSAにも関わらず、ヘッダーのalgがSHAの場合にはエラーにすれば良いとのこと。