javascript - Android Webview,formhash 在某些 Android 设备上不工作

标签 javascript android html hash webview

我一直在 Android 和 iOS 上开发网络应用程序并使用 WebView 。在 iPhone 上一切正常,但在 Android 上却不能在所有设备上正常工作,这让我抓狂。在五台 Android 设备上它运行良好,但在两台设备上它不会比登录页面更进一步。但是,它确实适用于浏览器中的移动网站(而非应用程序)。

移动应用程序无法运行的设备是 HTC One (v4.3) 和 Acer Liquid Z3 (v4.2)。另一台设备也是 HTC One (v4.3) 它确实可以工作,这使得问题很难理解和解决。

应用程序打开时的第一个窗口是一个简单的登录窗口。在它不工作的设备上,它只是重新加载页面,用户可以再次登录。登录信息与数据库中的详细信息进行核对。当它正常工作(或在浏览器中打开)时,它会加载到一个新页面。

主要 Activity .java:

public class MainActivity extends Activity {

WebView mWebView;
private ProgressBar loadingProgressBar;

@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

    setContentView(R.layout.activity_main);

    mWebView = (WebView) findViewById(R.id.webview);

    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.setWebViewClient(new DivumWebViewClient());

    mWebView.loadUrl("http://www.xxxx.com/index.php");

    loadingProgressBar = (ProgressBar) findViewById(R.id.progressbar_title);
    mWebView.setWebChromeClient(new WebChromeClient() {
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
            loadingProgressBar.setProgress(newProgress);
            if (newProgress == 100) {
                loadingProgressBar.setVisibility(View.GONE);
            } else {
                loadingProgressBar.setVisibility(View.VISIBLE);
            }
        }
    });

}

private class DivumWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        return true;
    }
}
}

索引.php

.....
<body class="blue-bg">
<?php
if (isset($_GET['error'])) {
    echo '<p class="error">Error Logging In!</p>';
} 
sec_session_start(); 
if (isset($_POST['email'], $_POST['p'])) {
    $email = $_POST['email'];
    $password = $_POST['p']; 

    if (login($email, $password, $mysqli) == true) {
        // Login success 
        header('Location: dashboard.php');
        exit;
    } else if(login($email, $password, $mysqli) == false){
        $error['error'] = "<p>Enter login details:</p>\n";
    }
} 
?>  
<div class="signin" style="margin-top: 0;">

    <div class="signin-body">

        <a href="index.php" title="Login" class="pull-right">
            <img src="../assets/images/logo.jpg" title="Login" alt="Login">
        </a>
        <br><h3>Login</h3>
        <?=$error['error']?>
        <form action="<?=$_SERVER['PHP_SELF']?>" id="login-validatie" method="post"        name="login_form">                  
            <div class="form-group">
             <input type="text" class="form-control" placeholder="Emailadres" name="email" id="email">
            </div>

            <div class="form-group">
             <input type="password" class="form-control" placeholder="Wachtwoord" name="password" id="password">
            </div>


            <div class="form-group clearfix">
            <input type="submit" onclick="formhash(this.form, this.form.password);" class="btn btn-med blue-bg pull-right" value="Inloggen">
            </div>

            <hr>          
        </form>

    </div>

</div>
<script src="../assets/js/scripts.js"></script>    
</body>
</html>

不知道是bug还是什么。奇怪的是它适用于大多数设备,但不适用于某些设备。它也适用于浏览器,这让我觉得它与 Android 中的 WebView 有关。我处于死胡同,感谢每一个帮助。谢谢!

更新 我终于找到了问题所在,它与表单散列有关。密码在 web View 中的某些 Android 设备上给出了不同的 sha512 哈希值,这使得无法登录。不知道是不是Android的web view在某些设备上的限制,有谁知道如何解决这个问题?

表单.js

function formhash(form, password) {
    // Create a new element input, this will be our hashed password field. 
    var p = document.createElement("input");

    // Add the new element to our form. 
    p.name = "p";
    p.type = "hidden";
    p.value = hex_sha512(password.value);

    form.appendChild(p);

    // Make sure the plaintext password doesn't get sent. 
    password.value = "";

    // Finally submit the form. 
    form.submit();
}

函数.php

function login($email, $password, $mysqli) {
    // Using prepared statements means that SQL injection is not possible. 
    if ($stmt = $mysqli->prepare("SELECT id, username, password, salt FROM x WHERE email = ? LIMIT 1")) {
        $stmt->bind_param('s', $email);  // Bind "$email" to parameter.
        $stmt->execute();    // Execute the prepared query.
        $stmt->store_result();

        // get variables from result.
        $stmt->bind_result($user_id, $username, $db_password, $salt);
        $stmt->fetch();

        // hash the password with the unique salt.
        $password = hash('sha512', $password . $salt);
        ?><script> var x; x = "<?php print($password); ?>"; console.log("Logging: password is " + x); </script><?

        if ($stmt->num_rows == 1) {
            // If the user exists we check if the account is locked
            // from too many login attempts 

            if (checkbrute($user_id, $mysqli) == true) {
                // Account is locked 
                // Send an email to user saying their account is locked
                return false;
            } else {
                // Check if the password in the database matches
                // the password the user submitted.
                if ($db_password == $password) {
                    // Password is correct!
                    // Get the user-agent string of the user.
                    $user_browser = $_SERVER['HTTP_USER_AGENT'];
                    // XSS protection as we might print this value
                    $user_id = preg_replace("/[^0-9]+/", "", $user_id);
                    $_SESSION['user_id'] = $user_id;
                    // XSS protection as we might print this value
                    $username = preg_replace("/[^a-zA-Z0-9_\-]+/", 
                                                            "", 
                                                            $username);
                    $_SESSION['username'] = $username;
                    $_SESSION['login_string'] = hash('sha512', 
                          $password . $user_browser);
                    // Login successful.
                    return true;
                } else {
                    // Password is not correct
                    // We record this attempt in the database
                    $now = time();
                    $mysqli->query("INSERT INTO login_attempts(user_id, time)
                                VALUES ('$user_id', '$now')");
                    return false;
                }
            }
        } else {
            // No user exists.
            return false;
        }
    }
}

在 iPhone 应用程序、Android 浏览器、桌面浏览器或某些 Android 应用程序上使用时,它会提供一个 sha5 哈希值:c7d9a2def4f8d0f9c4b65d7522566ed33549b266174b2b12ae7f7b047e7efed2e92d18e552d1c812f073e794d16feb8ccf9df85399c475f24571472dece2d9b2

但在某些 Android 设备上,由于某些奇怪的原因使用相同的密码时,它会给出两个哈希值之一: 98488504186f9f69041c80217c311cfb4772f46319c945d3bc30c0c2db5650e675774bc6978749770b598e70d4553ec0391e7d3ec0b56d51eef51eeadbb7e10e

a3e08c365ef82d4256d8e58fd63b53d63d50b6b3cac3cdaba395cc73289e5f955491f11f06408c2c6e6ae531d69ddb10f234ecef0cf375d9782abea27909c9ef

最佳答案

我之前也遇到过这个问题,我的 webview 无法在当前窗口中打开一个 url,不久之后 android os 会获取该 url 并尝试在浏览器中打开它。我有一个非常相似的实现。

我相信这直接来自 documentation 是您要寻找的:

创建和设置 WebViewClient 子类。当发生影响内容呈现的事情时将调用它,例如错误或表单提交。您还可以在此处拦截 URL 加载(通过 shouldOverrideUrlLoading())。

shouldOverrideUrlLoading() 方法告诉 webview 我想处理通过此 WebView 提交的所有 url 的加载操作

您可以在 My Github Project 从第 226 行开始看到我是如何处理这个问题的,我在其中添加了一个额外的内部类,它扩展了 WebViewClient 类。

边注

这适用于我支持的大多数设备上的应用程序。但您可能还想确保您的 URL 是完全合格的。我发现当我使用的任何网址都没有

http://

在它的前面,WebView 将无法加载 URL,即使使用 Additional WebViewClient。对象和 shouldOverrideUrlLoading() 调用。

您是否在加载失败后尝试过以下操作?看看这是否会刷新 webview 的状态,一旦刷新,就向您真正想要的 URL 发出新请求。

WebView.loadUrl("about:blank")

您试过在 WebView 中不使用 javascript 吗?

我听说这可能是一个潜在的安全漏洞,并且它对呈现网页的 WebView 有相当大的影响。

祝你好运!

更新

看起来您的问题不在于您的 webview,而是您的 php 脚本是否正确?

尝试在 Java 中使用这个创建密码时,或者检查用户密码是否正确:

String password = "123456"; 
MessageDigest md = MessageDigest.getInstance("SHA-256"); 
md.update(password.getBytes()); 
byte byteData[] = md.digest();

您实际上只需要在应用程序或服务器脚本的一侧执行此操作。我会从应用程序端选择,因为这样您可以通过网络而不是纯文本发送散列密码。

关于javascript - Android Webview,formhash 在某些 Android 设备上不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21888374/

相关文章:

javascript - 使用 JavaScript 或扩展获取 Firefox 页面信息

javascript - 无法使用 Dojo 获取名称属性

android - 有什么方法可以通过 android 服务检测音量键按下或音量变化吗?

javascript - 使用悬停图像效果的最有效方式

基于 JavaScript 的数据库服务于 JSON?

android - 无法在 AndroidStudio 2.1 Beta 中从 GitHub 克隆

java - _ClassInstance 符号?

javascript - SVG - 全局属性和事件列表?

html - bootstrap3 nav-tabs 不切换标签

html - 带标签的圆形导航 Bootstrap