如何安全是我的PHP登录系统? [英] How secure is my PHP login system?

查看:109
本文介绍了如何安全是我的PHP登录系统?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是新来的PHP,这也是我第一次登录系统,因此这将是巨大的,如果你们能看在我的code和看你能不能发现任何安全漏洞:

I'm new to PHP and this is also my first log in system so it would be great if you guys could look over my code and see if you can spot any security holes:

请注意:我消毒所有的用户输入,虽然它没有在这里显示。

note: I am sanitizing all user input although it's not shown here.

第1步:我以用户选择的密码,并通过这个功能运行它:

Step 1: I take the password the user chose and run it through this function:

encrypt($user_chosen_password, $salt);

function encrypt($plain_text, $salt) {
    if(!$salt) {
        $salt = uniqid(rand(0, 1000000));
    }
    return array(
        'hash' => $salt.hash('sha512', $salt.$plain_text),
        'salt' => $salt
    );
}

第二步:我然后存储哈希和盐( $密码['散'] $密码['盐'] 在数据库中的用户表):

Step 2: I then store the hash and the salt ($password['hash'] and $password['salt']) in the users table in the database:

id | username | password  | salt       | unrelated info...
-----------------------------------------------------------
1  | bobby    | 809a28377 | 809a28377f | ...
                fd131e5934
                180dc24e15
                bbe5f8be77
                371623ce36
                4d5b851e46

登录

第1步:我把用户输入的用户名,并做了查找数据库,看是否在返回任何行。在我的网站没有2用户可以共享同一个
用户名,使用户名字段总是有一个独特的价值。如果我返回1行我抢盐该用户。

Log In:

Step 1: I take the username the user entered and do a look up on the database to see if any rows are returned. On my site no 2 users can share the same username so the username field always has a unique value. If I get 1 row returned I grab the salt for that user.

第二步:,然后我运行用户通过加密功能,输入的密码(如$ P $以上pviously发布),但这个时候,我还供应从数据库中检索到的盐:

Step 2: Then I run the user entered password through the encrypt function (as previously posted above) but this time I also supply the salt retrieved from the database:

encrypt($user_entered_password, $salt);

第3步:我现在有正确的密码在这个变量匹配: $密码['散'] 。所以我所以数据库上的第二查找以查看是否
输入的用户名和密码散列一起返回一行。如果是这样,那么用户的凭据是正确的。

Step 3: I now have the proper password to match against in this variable: $password['hash']. So I so a second lookup on the database to see if the username entered and the hashed password together return a single row. If so then the user's credentials are correct.

第四步:为了使用户登录后,在他们的凭据传递我生成一个随机唯一的字符串和散列它:

Step 4: In order to log the user in after their credentials passed I generate a random unique string and hash it:

$random_string = uniqid(rand(0, 1000000));
$session_key = hash('sha512', $random_string);

我然后插入 $ session_key可以到数据库的 active_sessions 表:

user_id | key
------------------------------------------------------------
1       | 431b5f80879068b304db1880d8b1fa7805c63dde5d3dd05a5b

第五步:

我把( $ random_string )的最后一步所产生的未加密的唯一字符串,并设置为一个cookie我称之为的价值 active_session

I take the unencrypted unique string generated in the last step ($random_string) and set that as the value of a cookie which I call active_session:

setcookie('active_session', $random_string, time()+3600*48, '/');

第六步:

在顶部我的的header.php 包含有这样的检查:

At the top of my header.php include there is this check:

if(isset($_COOKIE['active_session']) && !isset($_SESSION['userinfo'])) {
   get_userinfo();
}

get_userinfo()函数不会对用户查找数据库表中,并返回一个关联数组,存储在一个称为会话用户信息

The get_userinfo() function does a lookup on the users table in the database and returns an associative array which is stored in a session called userinfo:

//首先这个函数将active_session cookie的值和散列它得到了session_key可以:

// first this function takes the value of the active_session cookie and hashes it to get the session_key:

hash('sha512', $random_string);

//那么它看到的 active_sessions 表中查找,如果这个创纪录的存在,如果是的话它会抢了 USER_ID 与该记录相关联,并使用该做的用户第二查找表获得用户信息

// then it does a lookup on the active_sessions table to see if a record by this key exists, if so it will grab the user_id associated with that record and use this to do a second lookup on the users table to get the userinfo:

    $_SESSION['userinfo'] = array(
        'user_id'           => $row->user_id,
        'username'          => $row->username,
        'dob'               => $row->dob,
        'country'           => $row->country,
        'city'              => $row->city,
        'zip'               => $row->zip,
        'email'             => $row->email,
        'avatar'            => $row->avatar,
        'account_status'    => $row->account_status,
        'timestamp'         => $row->timestamp,
    ); 

如果在用户信息会话存在我所知道的用户进行身份验证。如果它不存在,但那么 active_session cookie的存在检查
在顶部的的header.php 文件将创建的会话。

If the userinfo session exists I know the user is authenticated. If it doesn't exist but the active_session cookie exists then that check at the top of the header.php file will create that session.

为什么我独自使用Cookie,而不是会议的原因是坚持登录。因此,如果用户关闭浏览器会话可能会消失,但
cookie将仍然存在。而且,由于存在着支票在的header.php 的顶部,该会话将被重新创建,用户可以作为一个记录功能
在用户正常。

The reason why I am using a cookie and not sessions alone is to persist the login. So if the user closes the browser the session may be gone but the cookie will still exist. And since there is that check at the top of header.php, the session will be recreated and the user can function as a logged in user as normal.

第1步:无论是用户信息会话和 active_session 饼干都没有设置。

Step 1: Both the userinfo session and the active_session cookie are unset.

第二步: active_sessions 数据库中的表中的相关记录被删除

Step 2: The associated record from the active_sessions table in the database is removed.

注:我能看到的唯一问题(也许还有很多其他的),就是如果用户通过在其浏览器中创建自己这是假货 active_session 的cookie。当然,他们必须将作为cookie的值后,它是加密的,必须从那里我将检索 USER_ID在 active_sessions 表中的记录相匹配的字符串来创建会话。我不知道这样的机会是现实,为用户(可能使用自动程序),以正确地猜出一个字符串,他们不知道将被加密,SHA512和反对在 active_sessions 数据库表中获得用户ID来建立一个会话。

Notes: The only issue I can see (and perhaps there are many others), is if the user fakes that active_session cookie by creating it themselves in their browser. Of course they must set as that cookie's value a string which after it is encrypted must match a record in the active_sessions table from where I will retrieve the user_id to create that session. I am not sure what the chances of this is realistically, for a user (perhaps using an automated program) to guess a string correctly which they don't know will then be sha512 encrypted and matched against the string in the active_sessions table in the database to get the user id to build that session.

很抱歉的大文章,但因为这是我的网站这样一个重要组成部分,由于缺乏经验,我我只是想通过更多的有经验的开发人员来运行它,以确保它实际上是安全的。

Sorry for the big essay but since this is such a critical part of my site and due to my inexperience I just wanted to run it by more experienced developers to make sure it's actually safe.

那么你看到这条路线的任何安全漏洞和它如何改进?

So do you see any security holes in this route and how can it be improved?

推荐答案

您应该包括一些超时或故障转移对抗蛮力攻击prevent的。有许多方法可以做到这一点,包括基于IP的封锁,增量超时等,这一切都不会永远的停止黑客,但可以让它变得更加困难。

You should include some kind of timeout or failover to prevent against brute-force attacks. There are a number of ways to do this, including IP-based blocking, incremental timeouts, etc. None of these will ever stop a hacker, but they can make it much more difficult.

(你没有提到,所以我不知道你的计划)的另一点是失败的消息。让失败消息的含糊越好。提供了一个错误信息,如该用户名存在,但密码不匹配可能有助于最终用户,但它的杀死的登录功能。刚转换蛮力攻击,应采取为O(n ^ 2)时间 O(N) + O(N)。而不是需要尝试在彩虹表(例如)每置换,黑客只是会先尝试为用户名的值(用一组密码),直到失败消息的变化。然后,它的知道的有效用户,只是有蛮力的密码。

Another point (which you haven't mentioned, so I don't know your plan) is failure messages. Make failure messages as vague as possible. Providing an error message like 'That username exists, but the passwords did not match' might be helpful to the end-user, but it kills login functionality. You just converted a brute-force attack that should take O(n^2) time to O(n) + O(n). Instead of needed to try every permutation in a rainbow table (for example), the hacker just tries all values for username (with a set password) first, until the failure message changes. Then, it knows a valid user, and just has to brute force the password.

根据这些原则,你也应该确保当一个用户名存在,并且不存在相同的时间为止。当一个用户名确实存在您正在运行额外的进程。这样的反应,当存在VS时不输入用户名时间会更长。一个令人难以置信的技术黑客可以将页面停留时间的要求找到一个有效的用户名。

Along those lines, you should also make sure that the same amount of time elapses when a username exists and doesn't exist. You are running additional processes when a username actually exists. As such the response time would be longer when a username exists vs when it doesn't. An incredibly skilled hacker could time page requests to find a valid username.

同样,您应该确保,除到期的cookie,你也终止会话表。

Similarly, you should make sure that, in addition to expiring cookies, you also expire the sessions table.

最后,在 get_user_info()呼叫,您应该如果有多个并发的,活动的登录终止所有打开的会话。让闲置的一套金额(如30分钟)后,一定要超时的会话。

Lastly, in the get_user_info() call, you should terminate all open sessions if there are multiple concurrent, active logins. Make sure you timeout sessions after a set amount of inactivity (like 30 minutes).

沿着什么@格雷格Hewgill提到的线,你没有任何包含以下内容:

Along the lines of what @Greg Hewgill mentioned, you haven't included any of the following:


  • 服务器 - 客户端之间的SSL /加密连接

  • 你多少使用来处理身份验证(如OAuth的)
  • 其他传输协议

服务器的是安全的,但它并没有多么赫然保护你的算法是,如果有人可以读取的交换的数据(MITM)。你应该确保你只通信的加密协议。

You server is secure, but it doesn't matter how awesomely secure your algorithm is if someone can read the data that's exchanged (MITM). You should make sure you are only communicating over an encrypted protocol.

这篇关于如何安全是我的PHP登录系统?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆