SSL 替代 - 使用 JavaScript 加密密码提交给 PHP 进行解密

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5724650/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 18:08:34  来源:igfitidea点击:

SSL Alternative - encrypt password with JavaScript submit to PHP to decrypt

phpjavascriptencryptionsslpublic-key-encryption

提问by zuallauz

I'm building a website and my payment methods will be Google Checkout and Paypal. There will be links/buttons which will redirect the user to the secure Google/Paypal sites for processing the payments. This means I do not need the $150/year added expense and complexity of installing SSL certificates for my site.

我正在建立一个网站,我的付款方式将是 Google Checkout 和 Paypal。将有链接/按钮将用户重定向到安全的 Google/Paypal 站点以处理付款。这意味着我不需要每年 150 美元的额外费用和为我的站点安装 SSL 证书的复杂性。

However I would like to encrypt user's passwords as they are logging in so that if they are on a network some malicious person running FireSheep etc can't read the user's actual password as it is being sent to the server. The rest of the site doesn't need encryption as it's not really sensitive data and would probably slow the user experience down significantly.

但是,我想在用户登录时加密用户的密码,这样如果他们在网络上,一些运行 FireSheep 等的恶意人员就无法读取用户的实际密码,因为它被发送到服务器。网站的其余部分不需要加密,因为它不是真正的敏感数据,并且可能会显着降低用户体验。

My thoughts are this could be implemented with public key cryptography. Lets say the process goes something like this:

我的想法是这可以用公钥加密来实现。可以说这个过程是这样的:

  1. Public key is in the JavaScript external file, private key in PHP on the server
  2. User enters their username and password into the form and clicks submit
  3. The JavaScript runs and encrypts the password, storing it back in the text field
  4. Form is submitted to server and the password is decrypted with PHP
  5. Plain text password in PHP is salted & hashed then compared to hash in database.
  6. Possible similar process for the registration/change password functions.
  1. 公钥在 JavaScript 外部文件中,私钥在服务器上的 PHP 中
  2. 用户在表单中输入他们的用户名和密码,然后点击提交
  3. JavaScript 运行并加密密码,将其存储回文本字段
  4. 表单提交到服务器,密码用PHP解密
  5. PHP 中的纯文本密码被加盐和散列,然后与数据库中的散列进行比较。
  6. 注册/更改密码功能的可能过程类似。

I'm thinking something like RSA would do the trick. But I've hunted around the net for a working JavaScript library to do it but none seem to be compatible with the PHP libraries available. At any rate it needs to generate a set of keys that are compatible with the JavaScript and PHP.

我在想像 RSA 这样的东西可以解决问题。但是我已经在网上寻找一个可用的 JavaScript 库来完成它,但似乎没有一个与可用的 PHP 库兼容。无论如何,它需要生成一组与 JavaScript 和 PHP 兼容的密钥。

Anyone know of an actual working solution for this? If not how about we write one then open source it. Unfortunately writing encryption/decryption code is pretty complex so I don't really know exactly what the existing libraries are doing and how to modify them to make it work. I already have protection for session fixation/hiHymaning so I'm not interested in that. Just interested in encrypting the data before it gets to the web server.

任何人都知道一个实际的工作解决方案吗?如果不是我们写一个然后开源它怎么样。不幸的是,编写加密/解密代码非常复杂,所以我真的不知道现有库在做什么以及如何修改它们以使其工作。我已经有了会话固定/劫持的保护,所以我对此不感兴趣。只是对在数据到达 Web 服务器之前加密数据感兴趣。

NB: Please don't post a bunch of links to standalone Javascript or PHP encryption libraries, I've found those already on Google. That's not actually useful. What I need is code for JavaScript encryption AND PHP decryption that actually works together harmoniously to produce the intended result outlined above.

注意:请不要发布一堆指向独立 Javascript 或 PHP 加密库的链接,我已经在 Google 上找到了这些链接。这实际上没有用。我需要的是 JavaScript 加密和 PHP 解密的代码,它们实际上可以和谐地协同工作以产生上面概述的预期结果。

Also if you could refrain from posting comments like "just use SSL". I'd actually like a solution to this exact problem even if it's not best practice, it would be interesting none the less.

此外,如果您可以避免发布诸如“仅使用 SSL”之类的评论。我实际上想要一个解决这个确切问题的方法,即使它不是最佳实践,但它仍然很有趣。

Many thanks!

非常感谢!

采纳答案by Martin Vseticka

http://www.jcryption.org/-- Is the combination you are looking for.

http://www.jcryption.org/-- 是您正在寻找的组合。

回答by deceze

Only one problem: An attacker does not need to know the actual password. All he needs to see is the value that is sent to the server. This value allows the user to log in. It does not matter what that value is; whether it's plaintext, encrypted text or a picture of a cat. It's just a token that authenticates the user. If an attacker can see this token and repeat the same request and that same request allows him to log in, you gained nothing.

只有一个问题:攻击者不需要知道实际密码。他需要看到的只是发送到服务器的值。该值允许用户登录。该值是什么并不重要;无论是明文、加密文本还是猫的图片。它只是一个对用户进行身份验证的令牌。如果攻击者可以看到此令牌并重复相同的请求,并且相同的请求允许他登录,那么您将一无所获。

回答by Jeffrey Hantin

RSA is overkill; what you probably need is a simple challenge-response protocol. For example:

RSA 是矫枉过正;您可能需要的是一个简单的质询-响应协议。例如:

  • Generate a random nonce value; this helps prevent replay attacks.
  • Send that nonce value and the password salt to the browser along with the rest of the login form.
    • You are storing passwords in salted and hashed form, right?
  • When the user enters a password, have the script on the form compute and send back hash(hash(password, salt), nonce) instead.
  • When the server receives the form submission, have it compute hash(storedSaltedPassword, nonce) and verify that it equals the submitted value.
    • Retain the nonce value at the server; don't trust the client to echo it back to you, or your replay protection is gone.
  • 生成一个随机的 nonce 值;这有助于防止重放攻击。
  • 将该 nonce 值和密码 salt 与登录表单的其余部分一起发送到浏览器。
    • 您以加盐和散列形式存储密码,对吗?
  • 当用户输入密码时,让表单上的脚本计算并发送回 hash(hash(password, salt), nonce) 代替。
  • 当服务器收到表单提交时,让它计算 hash(storedSaltedPassword, nonce) 并验证它是否等于提交的值。
    • 在服务器上保留 nonce 值;不要相信客户端会将其回显给您,否则您的重放保护就会消失。

The weakness of this scheme is that the password hashes in the database are in some sense password-equivalent; while it's likely infeasible to extract the original password used to produce those hashes, knowledge of the stored hash is sufficient to impersonate the user on your site.

这种方案的弱点是数据库中的密码散列在某种意义上是密码等价的;虽然提取用于生成这些散列的原始密码可能不可行,但对存储的散列的了解足以在您的站点上冒充用户。

SSL certificates serve an entirely different purpose: the purpose of an SSL certificate is to make it difficult for a third-party rogue server to claim to be your server, because it doesn't have a certificate signed by some mutually trusted third party that it belongs on your domain. On the other hand, if you can't stop a rogue server from impersonating yours, you can't protect your users from giving their password to that rogue server, cryptography notwithstanding.

SSL 证书用于完全不同的目的:SSL 证书的目的是让第三方流氓服务器难以声称是您的服务器,因为它没有由某个相互信任的第三方签署的证书属于您的域。另一方面,如果你不能阻止一个流氓服务器冒充你的服务器,你就不能保护你的用户不将他们的密码提供给那个流氓服务器,尽管有密码学。

回答by zuallauz

First, I don't think this is a good idea. I found some examples using Google that may be useful for you (I have not tested these, however):

首先,我认为这不是一个好主意。我找到了一些使用 Google 的示例,它们可能对您有用(但是,我还没有测试过这些):

GPL JavaScript Public Key Encryption

GPL JavaScript 公钥加密

RSA Public Key Encryption Test in JavaScript

JavaScript 中的 RSA 公钥加密测试

PGP Encryption in JavaScript

JavaScript 中的 PGP 加密

RSA Algorithm Example in JavaScript

JavaScript 中的 RSA 算法示例

You should establish some salting mechanism to salt every encrypted value otherwise the key could get compromised.

您应该建立一些加盐机制来加盐每个加密值,否则密钥可能会被泄露。

回答by user207421

You don't need to encrypt the password. You need to hashthe password. You really really don't want to have any access to the plaintext password yourself whatsoever, otherwise you lose non-repudiation, which has seriouslegal consequences. You need to investigate the meaning of this thoroughly before proceeeding.

您不需要加密密码。您需要对密码进行哈希处理。你真的真的不想自己有任何访问明文密码的机会,否则你就失去了不可否认性,这会产生严重的法律后果。在继续之前,您需要彻底调查其含义。

回答by Dibyendu Konar

This is the code to take the input and then encrypt the content by java script The entire code is also available in github.you guys can search for it encrypt_js_decrypt_php. The problem was running since long.I have come up with the solution.Just import it into localhost.

这是获取输入然后通过java脚本加密内容的代码,整个代码在github上也有,大家可以搜索encrypt_js_decrypt_php。问题一直存在。我已经想出了解决方案。只需将其导入本地主机即可。

<html>

<input type="text" id="code" name="code"/>
<input type="submit" name="submit" value="submit" onclick="return encryptCode();"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript">
function rc4(key, str)
{
    var s = [], j = 0, x, res = '';
    for (var i = 0; i < 256; i++) 
    {
        s[i] = i;
    }
    for (i = 0; i < 256; i++) 
    {
        j = (j + s[i] + key.charCodeAt(i % key.length)) % 256;
        x = s[i];
        s[i] = s[j];
        s[j] = x;
    }
    i = 0;
    j = 0;
    for (var y = 0; y < str.length; y++) 
    {
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;
        x = s[i];
        s[i] = s[j];
        s[j] = x;
        res += String.fromCharCode(str.charCodeAt(y) ^ s[(s[i] + s[j]) % 256]);
    }
    return res;
}

function encryptCode()
{
  var value = document.getElementById("code").value;
  var key = "secretKeyToProvide";  /*--Provide Your secret key here--*/
  var codeValue = rc4(key, value);
  var arr = {code:codeValue, Age:25};
  $.ajax({
                url: "response.php",
                type: "POST",
                data: JSON.stringify(arr),
                dataType: 'json',
                async: false,
                contentType: 'application/json; charset=utf-8',
                success: function(data) 
                {
                    alert(data);
                }
            });   
}
</script>
</html>

Now,lets decrypt the code in php

现在,让我们解密php中的代码

<?php

function mb_chr($char) 
{
    return mb_convert_encoding('&#'.intval($char).';', 'UTF-8', 'HTML-ENTITIES');
}

function mb_ord($char)
{
    $result = unpack('N', mb_convert_encoding($char, 'UCS-4BE', 'UTF-8'));
    if (is_array($result) === true) 
    {
        return $result[1];
    }
        return ord($char);
}

function rc4($key, $str) 
{   
    if (extension_loaded('mbstring') === true) 
    {
        mb_language('Neutral');
        mb_internal_encoding('UTF-8');
        mb_detect_order(array('UTF-8', 'ISO-8859-15', 'ISO-8859-1', 'ASCII'));
    }
    $s = array();
    for ($i = 0; $i < 256; $i++)
    {
        $s[$i] = $i;
    }
    $j = 0;
    for ($i = 0; $i < 256; $i++)
    {
        $j = ($j + $s[$i] + mb_ord(mb_substr($key, $i % mb_strlen($key), 1))) % 256;
        $x = $s[$i];
        $s[$i] = $s[$j];
        $s[$j] = $x;
    }
    $i = 0;
    $j = 0;
    $res = '';
    for ($y = 0; $y < mb_strlen($str); $y++)
    {
        $i = ($i + 1) % 256;
        $j = ($j + $s[$i]) % 256;
        $x = $s[$i];
        $s[$i] = $s[$j];
        $s[$j] = $x;
        $res .= mb_chr(mb_ord(mb_substr($str, $y, 1)) ^ $s[($s[$i] + $s[$j]) % 256]);
    }
    return $res;
}

$request_body = file_get_contents('php://input');
$json = json_decode($request_body);
$secretCode =$json->code ;
$age =$json->Age  ;
$key = "secretKeyToProvide";  /*--Provide Your secret key here what you have given in javascript--*/
$decryptedSecretCode  = rc4($key, $secretCode) ;
echo $decryptedSecretCode;
exit;
?>