Android LintのDetectorを読む Day1: AddJavascriptInterfaceDetector
背景
WebView#addJavascripInterface
によりアプリからオブジェクトを埋め込む関数だが、WebView中のJavaScriptがリフレクション使ってアプリ側のフィールドにアクセス出来る脆弱性があるため。
API17移行では @JavascriptInterface
がついているメソッドしかJavaScriptからアクセスできないが、それ以下だとすべてのメソッドにアクセス可能。
条件
- minSdkVerが17未満
WebView.addJavascriptInterface(objct, string)
TargetApi
RequiresApi
のアノテーションで17以上がついていない
コード読んだ上での気づき
メソッドについて検出の仕方
メソッドに対してLintで検出したい場合、 SourceCodeScanner
を継承し getApplicableMethodNames
visitMethodCall
を実装すること。
class AddJavascriptInterfaceDetector : Detector(), SourceCodeScanner { // ---- implements SourceCodeScanner ---- override fun getApplicableMethodNames(): List<String> = listOf(ADD_JAVASCRIPT_INTERFACE) override fun visitMethodCall( context: JavaContext, node: UCallExpression, method: PsiMethod ) { } } #疑問 minSdkに関係する判定が3度入っていて処理が重複していそうなものだけれどどうなんだろう。 一つ目はわかりやすい。
if (context.project.minSdk >= 17) {
return
}
2つ目について、
if (isSuppressed(context, API_17, node, context.project.minSdkVersions)) {
return
}
でありisSuppressedの冒頭が以下なので、1つ目の判定が同時に行われていそうではある。 処理としては重複しているが、意味合いが異なる (こちらはsuppressされてるかのチェック)のでよさそう。
fun isSuppressed(
context: JavaContext,
api: ApiConstraint,
element: UElement,
minSdk: ApiConstraint
): Boolean {
if (minSdk.isAtLeast(api)) {
return true
}
3つ目について、17未満でレポートするようなコードになっている。 reportについてのコメントでは、 context.projectで取れるのはソースコードのプロジェクト、つまりライブラリだったらライブラリ。 ライブラリのminSdkVerが17未満でも使っているメインのPJで17以上だったら問題ないので、そのための紀伊術。 ちなみにlintの仕組み的に 1. ライブラリのソースファイルからlintチェックを行い、潜在的なエラーを報告する 2. appモジュールなど下流のモジュールでレポートを生成する時、そこでのminSdkVerなどでフィルタリングする となっているので、 判定に `context.main` を使うのは違うようだ。
context.report(incident, minSdkLessThan(17))