简体   繁体   English

使用令牌(Java)保护REST Web服务

[英]Securing REST Web Service using token (Java)

This question is in some way related to the below linked question. 这个问题在某种程度上与以下相关问题有关。 However, I need a little more clarity on some aspects and some additional information. 但是,我需要更清楚一些方面和一些其他信息。 Refer: REST Web Service authentication token implementation 请参阅: REST Web服务身份验证令牌实现

Background: 背景:

  • I need to implement security for a REST Web Service using token 我需要使用令牌为REST Web服务实现安全性
  • The webservice is intended for use with Java client. Web服务旨在与Java客户端一起使用。 Hence, form authentication and popups for credentials are not useful. 因此,凭据的表单身份验证和弹出窗口无用。
  • I'm new to REST security and encryption 我是REST安全和加密的新手

This is what I have understood till now: 这是我迄今所理解的:

For first request: 第一次请求:

  1. User establishes https connection (or container ensures https using 301) 用户建立https连接(或容器使用301确保https)
  2. User POSTs username and password to login service 用户POST用户名和密码登录服务
  3. If credentials are valid we: 如果凭证有效,我们:
    • Generate a random temporary token 生成随机临时令牌
    • Store the random token on server mapping it to actual username 将随机令牌存储在服务器上,将其映射到实际用户名
    • Encrypt the token using a symmetric key only known to server 使用仅为服务器所知的对称密钥加密令牌
    • Hash the encrypted token 哈希加密的令牌
    • Send the encrypted token and the hash to the client 将加密的令牌和哈希发送到客户端

For subsequent requests: 对于后续请求:

  1. Client sends this encrypted token and hash combination (using username field of basic?) 客户端发送此加密令牌和哈希组合(使用基本的用户名字段?)
  2. We make sure the encrypted token is not tampered using the hash and then decrypt it 我们确保加密的令牌不会被哈希篡改,然后解密
  3. We check the decrypted token in the session-tracking-table for a not-expired entry and get the actual username (expiry to be managed by code?) 我们检查session-tracking-table中的解密令牌是否有未过期的条目,并获取实际的用户名(到期时间由代码管理?)
  4. If the username is found, based on allowed roles, allowed operations are configured 如果找到用户名,则根据允许的角色配置允许的操作

More details: 更多细节:

  1. Since client is a java client, the first request can be a POST containing the credentials. 由于客户端是java客户端,因此第一个请求可以是包含凭据的POST。 However, this looks like it may expose the credentials before the https gets established. 但是,这似乎可能会在https建立之前公开凭据。 Hence should there be a dummy GET to a secured resource so that https is established first? 因此,是否应该对安全资源进行虚拟GET,以便首先建立https?
  2. Assuming above is required, the second request is a LoginAction POST with credentials. 假设上面是必需的,第二个请求是带有凭据的LoginAction POST。 This request is handled manually (not using container's authorisation). 此请求是手动处理的(不使用容器的授权)。 Is this right? 这是正确的吗?
  3. The above LoginAction returns the user the combination of encrypted token + hash 上面的LoginAction返回用户加密令牌+哈希的组合
  4. User sets it to the header that is used by BASIC authentication mechanism (field username) 用户将其设置为BASIC身份验证机制使用的标头(字段用户名)
  5. We implement a JAASRealm to decrypt and validate the token, and find the roles allowed 我们实现了一个JAASRealm来解密和验证令牌,并找到允许的角色
  6. The rest of authorisation process is taken care of by the container with the WebResourceCollection defined in the web.xml 其余的授权过程由具有web.xml中定义的WebResourceCollection的容器负责

Is this the correct approach? 这是正确的方法吗?

Why not simplify it to the following? 为什么不将它简化为以下内容?

For first request: 第一次请求:

  1. User establishes HTTPS connection to server (service does not listen on any other ports) and POSTs credentials to login service. 用户建立与服务器的HTTPS连接(服务不在任何其他端口上侦听)和POST登录服务的凭据。
  2. Server replies with HSTS header to ensure all further communication is HTTPS. 服务器回复HSTS标头以确保所有进一步的通信都是HTTPS。
  3. If credentials are valid we: 如果凭证有效,我们:
    • Generate a random temporary token which is securely generated using a CSPRNG . 生成使用CSPRNG安全生成的随机临时令牌。 Make this long enough to be secure (128 bit). 使这长得足够安全(128位)。
    • Store the random token on server mapping it to actual username. 将随机令牌存储在服务器上,将其映射到实际用户名。
    • Send the random token to the client 将随机令牌发送到客户端

For subsequent requests: 对于后续请求:

  1. Client sends token in a custom HTTP header over HTTPS. 客户端通过HTTPS在自定义HTTP标头中发送令牌。
  2. Token is located in the DB and mapped to the username. 令牌位于数据库中并映射到用户名。 If found access is configured based on allowed roles and allowed operations. 如果找到基于允许的角色和允许的操作的访问权限。
  3. If not found user is considered unauthenticated and will have to authenticate with the login service again to get a new token. 如果未找到,则认为用户未经身份验证,并且必须再次使用登录服务进行身份验证才能获得新令牌。

On the server side the token will be stored with an expiry date. 在服务器端,令牌将以失效日期存储。 On each access to the service this date will be updated to create a sliding expiration. 在每次访问服务时,将更新此日期以创建滑动到期日期。 There will be a job that will run every few minutes to delete expired tokens and the query that checks the token for a valid session will only check those that have not deemed to have expired (to prevent permanent sessions if the scheduled job fails for any reason). 每隔几分钟就会有一个作业删除已过期的令牌,并且检查令牌以查找有效会话的查询只会检查那些未被认为已过期的查询(如果预定的作业因任何原因失败,则会阻止永久会话)。

There is no need to hash and encrypt the tokens within the database - it adds no real value apart from a touch of security through obscurity . 不需要对数据库中的令牌进行散列加密 - 除了通过默默无闻安全性之外,它不会增加真正的价值。 You could just hash though. 你可以哈哈哈哈。 This would prevent an attacker that managed to get at the session data table from hijacking existing user sessions. 这可以防止设法进入会话数据表的攻击者劫持现有用户会话。

The approach looks ok. 方法看起来不错。 Not very secure. 不太安全。 Let me highlight some of the attacks possible with the request. 让我强调一下该请求可能发生的一些攻击。

  1. Man-In-the-middle attack in a POST request, the user can tamper with the request and server does not have any way to ensure the data is not tampered. 在POST请求中的中间人攻击,用户可以篡改请求,服务器无法确保数据不被篡改。

  2. Replay attack: In this, the attacker does not tamper with the request. 重播攻击:在此,攻击者不会篡改请求。 The attacker taps the request and sends it to the server multiple times in a short duration, though it is a valid request, the server processes the request multiple times, which is not needed Please read about Nonce. 攻击者轻敲请求并在短时间内将其多次发送给服务器,虽然这是一个有效请求,服务器多次处理请求,这是不需要请阅读Nonce。

  3. In the first step, the user sends his credentials ie username and password to the login service and if you have a web based application that also uses the same password it might be dangerous. 在第一步中,用户将他的凭证(即用户名和密码)发送到登录服务,如果您的基于Web的应用程序也使用相同的密码,则可能是危险的。 If in case password in compromised, API and web everything is exposed, please use a different PIN for API access. 如果密码被泄露,API和Web上的所有内容都暴露出来,请使用不同的PIN进行API访问。 Also, ensure decrypted token as specified by you, expires after a certain time. 另外,确保您指定的解密令牌,在一定时间后过期。

  4. Ensure the service (application server) tomcat. 确保服务(应用程序服务器)tomcat。 jboss never returns a server page in case of internal error, this gives the attacker extra information of the server where the app is deployed. 如果发生内部错误,jboss永远不会返回服务器页面,这会为攻击者提供部署应用程序的服务器的额外信息。

-- MODIFIED BASED ON SECOND POST -- - 基于第二次修改的修改 -
Yes your correct if your using mutual SSL, but in case its a one way access you don't have the client certificates. 是的,如果您使用相互SSL,则是正确的,但如果是单向访问,则您没有客户端证书。 It would be good if you just double ensured everything in the request, just like signed (signature) SOAP, one of the strong data transfer mechanism. 如果你只是加倍确保请求中的所有内容,就像签名(签名)SOAP,强大的数据传输机制之一那样。 But replay attack is a possibility with HTTPS, just handle that. 但重放攻击是HTTPS的一种可能性,只需处理即可。 Rest use tokens encryption is good. 休息使用令牌加密是好的。 And why not ask the client to decrypt the token with the password and return the output of the decryption by this you can validate the output, if it is present in your database ? 为什么不让客户端用密码解密令牌并返回解密输出,你可以验证输出,如果它存在于你的数据库中? This approach the user does not send the password over the wire even if it is HTTPS ? 这种方法即使是HTTPS,用户也不会通过网络发送密码?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM