我可以以编程方式登录网站而无需以明文形式存储密码吗?

时间:2012-07-09 06:59:09

标签: security authentication screen-scraping

我做了很多涉及自动提交表单和/或从网站检索数据的项目。其中一些站点需要用户名/密码身份验证。 (这些网站没有API,所以我依赖于屏幕抓取。)

我见过的大部分教程都将源代码中的用户名和密码存储在任何其他POST数据中,例如:

string username = "someUserName";
string password = "somePassword";
// submit POST data...

但我知道以纯文本存储密码通常是不受欢迎的。我应该使用另一种方法吗?

6 个答案:

答案 0 :(得分:3)

存储密码的常用方法是对其进行散列。由于大多数散列密码的算法具有破坏性,即它们无法逆转,这对您无效。

一个选项是使用可逆散列,例如对密码进行base64编码,但它并不比以纯文本格式存储更安全。

据我所知,最好的解决方案是将密码存储在数据库中。如果您真的担心有人获取用户名和密码,您可以使用encryption functions在数据库中加密它们,或者您可以使用直接在磁盘上加密的SQLite数据库。

通过这种方式,您的代码和登录凭据是分开的,您可以安全地与他人共享代码而无需担心安全问题。

答案 1 :(得分:1)

我有一个需要解决此问题的抓取项目。我的设置包括两个独立的服务器第一个是用户前端Web应用程序。第二个是处理抓取的nodejs服务器。

我使用openssl密钥对加密处理加密。我为nodejs机器生成一个密钥对,并将公钥提供给前端Web应用程序。当用户注册其第三方凭证时,这些凭证将使用公钥加密并存储在数据库中。

网络应用会定期选择用户的加密凭据并将其发送到节点服务器,并使用私钥对其进行解密,并与第三方一起使用以进行抓取。

快速搜索后,我发现this有关使用openssl和加密字符串的文章。

我意识到这是一个非常古老的帖子,但希望它可以帮助下一个遇到这个问题的人。

答案 2 :(得分:0)

加密和解密的一种非常简单的方法是extended tiny encription algorithm (XTEA)。我在这里粘贴了维基百科的C ++代码,但请记住,任何人都可以在那里更改它。

#include <stdint.h>

/* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */

void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;
    for (i=0; i < num_rounds; i++) {
        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
        sum += delta;
        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
    }
    v[0]=v0; v[1]=v1;
}

void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;
    for (i=0; i < num_rounds; i++) {
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
    }
    v[0]=v0; v[1]=v1;
}

答案 3 :(得分:0)

你必须做两件事:
1.使用HTTPS登录页面(如有必要)
2.收到密码后立即使用密码加密。编码器是这样的:

private static String passwordEncryption(String oldPass){
    String newPass = "";
    try {
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");  
        messageDigest.update(oldPass.getBytes(), 0, oldPass.length());  
        newPass = new BigInteger(1,messageDigest.digest()).toString(16);  
        if (newPass.length() < 32) {
            newPass = "0" + newPass; 
        }
        return newPass;
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return newPass;

}


并使用MySql的 MD5()功能将收到的密码与存储的密码进行比较。

答案 4 :(得分:0)

我们使用的模式是:

在数据库表中,您有一个加密列。此列包含使用系统范围的长(128位)随机密钥(通常存储在配置文件中)加密的数据。 此加密列中的数据包含用于每个第三方服务的单独(随机)密钥。使用此密码,我们会加密与此第三方服务相关的身份验证详细信息。

为什么要进行双重加密?

您将纯文本密码的数量减少到一个(系统范围的密码)。因此,密钥管理更容易。 我们为每个第三方服务创建一个长的随机密钥,以便我们可以有选择地解密每个第三方服务的凭证,并在必要时在系统之间传输它们。将我们的一个密钥存储在数据库之外还可以降低与SQL注入攻击(它们只“获取数据库数据)和备份(配置文件不包含在常规备份数据中)相关的风险。

缺点显然是系统范围的密码。它需要在某处内存中。

我不是密码学家,我很确定以上是次优的。但是,它比仅以纯文本格式存储第三方服务凭证更有效,更易于管理和安全。

答案 5 :(得分:0)

没有办法做到这一点。它需要以纯文本(或“可逆加密”)的形式提供给脚本。

许多Apis(例如亚马逊网络服务)都会建议在环境变量中设置凭据,这可能与您希望的一样安全。

把它放在.bash_profile中,仔细检查perrmissions,至少你可以肯定它不会在公共仓库中的github上结束。