【问题标题】:PHP session handling for API of iOS appiOS 应用程序 API 的 PHP 会话处理
【发布时间】:2016-02-01 05:21:23
【问题描述】:

我正在编写一个简单的 PHP 后端。我不想在用户每次登录时都传输用户名/密码信息。相反,我想要一个基于令牌的身份验证系统。

我不明白如何将密钥加密到服务器和客户端上的令牌中并比较它们应该如何工作,或者它如何使系统更安全。

1) 是一个开源库,它抽象了令牌的创建以在这样的设置中使用吗?

2) 令牌过期时会发生什么?应该什么时候到期?每次有人使用应用程序并使用旧令牌发出请求时是否应该更新它?

3) 我最好还是硬着头皮使用 OAuth? 后端目前主要用于开发目的,如果包装我自己的令牌系统不太复杂,我认为最好。

【问题讨论】:

    标签: php ios oauth token backend


    【解决方案1】:

    我的回答可能不是最好的,但它应该能让你开始。

    假设您有一个包含字段的用户表

    user_id
    user_email
    user_salt
    user_password
    user_vtoken
    

    当您首次注册用户时,系统会提示他们输入电子邮件和密码。

    你应该做的是首先通过生成一个随机字符串(例如hoasyfgq39247t)来加盐密码,将其附加到密码的末尾(比如密码是“qwerty123”,它会变成“qwertyhoasyfgq39247t”)。然后你用你喜欢的任何东西(password_hash php函数,SHA3等)对加盐密码进行哈希处理,它应该给你一个一定长度的字符串(你可以在哈希时指定长度)。

    将电子邮件、散列/加盐密码和盐本身发送到您的服务器,在那里它创建一个具有唯一 user_id 的用户对象/行。您可以将 user_vtoken 默认为一些随机字符串(在创建用户时不要将其留空)。

    现在,当用户第一次登录时,他们会输入他们的电子邮件和密码。您应该首先向您的服务器发送一个请求,以检索附加到用户电子邮件中的“salt”。获得盐后,将其附加到他们输入的密码中,并使用他们登录时使用的相同算法对其进行哈希处理。那应该给你一个散列/加盐的字符串。将电子邮件和散列/加盐字符串发送到您的服务器并进行比较。如果散列密码与您存储在数据库中的密码匹配,则它们已通过身份验证。一旦发生这种情况,让服务器生成一个新的 user_vtoken(每次用户登录时都执行此操作)并将其返回给您的应用程序。

    一旦您的应用程序获得 user_vtoken,请将其存储在某处。现在,对于您对服务器的每个后续调用,包括 user_email/user_vtoken 组合(如果您在登录时返回 user_id,您也可以执行 user_id/user_vtoken 组合)。如果由于任何原因身份验证失败,请确保发回正确的错误代码并强制用户退出应用程序并将其带回登录屏幕。

    如果您不希望用户在应用重启时重新登录,您可以将 user_id/user_vtoken 存储在应用的持久内存中。

    何时重置 user_vtoken

    您需要在每次用户登录和每次用户注销时重置服务器端的 user_vtoken。这将在技术上注销当前登录到应用程序的任何人,因为他们存储的 user_vtoken 不再有效

    user_vtoken 是否应该过期?

    这取决于你。如果需要,您可以在每次生成新的 user_vtoken 时设置 user_vtoken_expiry 字段。当用户尝试使用过期的 user_vtoken 进行身份验证时,您可以强制他们重新登录。我通常从不这样做,因为这对用户来说很烦人,并且并没有真正让事情变得更加安全。您可能不希望每次用户使用一个身份验证时都生成一个新的 user_vtoken,因为它不提供任何额外的安全性,并且如果您的用户从不同的设备登录,您的应用程序将无法使用。

    加盐/散列是怎么回事

    您永远都不想在数据库中存储实际密码。仍然有数量惊人的白痴存储用户的实际密码,然后他们被破解,所有的地狱都崩溃了。事实上,您可能永远不希望实际密码离开客户端。在散列密码之前对密码加盐还可以防止人们在您被破解时使用预编译的字典对您的密码进行反散列处理。

    更安全

    通过 HTTPS 传递您的请求还可以降低您遭受中间人攻击的风险。如果您检测到来自新设备的新登录,您可能会变得更加严肃,并需要两步授权(通过短信或额外问题)。

    使用 Oauth?

    OAuth 非常强大,但如果您不熟悉这一切,则实施起来有点困难。自己构建可能会容易得多。

    希望这会有所帮助。

    【讨论】:

    • 谢谢,在密码到达后端之前,我没想到要散列密码。这样做完全有意义,但是攻击者仍然可以访问散列密码并使用它来登录。这里的好处是防止密码重用对用户造成伤害吗?现在我只是使用随机散列作为令牌。我记得读过一些关于建议制作的特殊令牌的内容,特定于协议(不确定它是否是 OAuth),但总的来说,系统按照您指定的方式工作。
    • 散列/加盐密码主要用于保护用户的实际密码,当然因为大多数人在一堆在线服务中使用相同的密码。现在,是的,攻击者理论上可以通过中间人攻击拦截散列密码,这就是 SSL 的用武之地。它通过加密保护浏览器和服务器之间的所有通信,因此没有人可以理解数据即使他们拦截它。另一种可能性是,有人闯入您的服务器并找到了您的用户数据库……在这种情况下,无论如何您都陷入了严重的困境。
    • 您还提到了我认为的密钥/公钥。密钥和公钥是数学上相关的密钥,您使用公钥加密的任何内容都只能由密钥解密。所以基本上你会在你的网站上提供公钥,加密发送出去的数据,然后用你存储在服务器中的密钥对其进行解密。这基本上就是 SSL(我在这里简化了很多事情),除了 SSL 用于您的域和服务器之间的所有通信。自己实现这一点没有多大意义。
    • 我会选择 OAuth,因为它会使事情更接近“标准”,并且会简化与其他系统/客户端/等的集成。在将来。 OAuth2 实现起来更简单,而且有很多库可以为您实现。
    • 这更多是个人意见,但我总是发现 OAuth2 比原始 OAuth 更倾向于企业化。还听说它实际上并不那么安全。
    【解决方案2】:

    你可以使用

        NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    
        [sessionConfiguration setAllowsCellularAccess:YES];
    
        [sessionConfiguration setHTTPAdditionalHeaders:@{ @"Accept" : @"application/json" }];
    
         NSURLSession *session = [NSURLSession  sessionWithConfiguration:sessionConfiguration];
    
         NSURL  *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@home/%@",LINK,str]];  
    
        // Configure the Request
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
        request.HTTPBody = [dataString dataUsingEncoding:NSUTF8StringEncoding];
        request.HTTPMethod = @"POST";
        [request setValue:[NSString stringWithFormat:@"%@=%@", strSessName, strSessVal] forHTTPHeaderField:@"Cookie"];
    
         NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
                                              {
                                                  // Handle the Response
                                                  if(error)
                                                  {
                                                    NSLog(@"%@",[NSString stringWithFormat:@"Please check your internet connection: %@", [error description]]);
    
                                                      // Update the View
                                                      dispatch_async(dispatch_get_main_queue(), ^{
    
       // Hide the Loader
         [self ShowConnectionError];
                                             });
                                                      return;
                                           }
    
                                                  NSArray * cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:request.URL];
                                                  for (NSHTTPCookie * cookie in cookies)
                                                  {
    
                                             NSLog(@"%@=%@",cookie.name, cookie.value);
    
                                             strSessName=cookie.name;
    
                                             strSessVal=cookie.value;
    
                                             NSLog(@"%@=%@", strSessName, strSessVal);
                                           // Here you can store the value you are interested in for example
                                                  }
    
    
    
    
                                                  dispatch_async(dispatch_get_main_queue(), ^{
    
                       ////load your view                              
    
    
    
    
    
    
                                                  });
    
    
    
    
                                              }];
    
        // Initiate the Request
        [postDataTask resume];
    

    【讨论】:

    • 这里不包含 PHP 代码,您只展示了客户端的操作。不过谢谢..
    • 在客户端我们只需要写session_start();在
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-20
    • 2012-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多