为移动应用程序创建 API - 身份验证和授权

发布于 2024-09-28 04:43:26 字数 1601 浏览 1 评论 0原文

概述

我希望为我的应用程序创建一个 (REST) API。最初/主要目的是供移动应用程序(iPhone、Android、Symbian 等)使用。我一直在研究基于 Web 的 API 的身份验证和授权的不同机制(通过研究其他实现)。我已经掌握了大部分基本概念,但仍在寻找一些领域的指导。我想做的最后一件事就是重新发明轮子,但我没有找到任何符合我的标准的标准解决方案(但是我的标准可能被误导,所以也请随意批评)。此外,我希望 API 对于使用它的所有平台/应用程序都是相同的。

oAuth

我将继续提出我对 oAuth 的反对意见,因为我知道这可能是第一个提供的解决方案。对于移动应用程序(或更具体地说是非 Web 应用程序),将应用程序(转到 Web 浏览器)进行身份验证似乎是错误的。此外,(据我所知)浏览器无法将回调返回到应用程序(尤其是跨平台)。我知道有几个应用程序可以做到这一点,但感觉不对,并且破坏了应用程序的用户体验。

要求

  1. 用户在应用程序中输入用户名/密码。
  2. 每个 API 调用都由调用应用程序识别。
  3. 开销保持在最低限度,并且身份验证方面对于开发人员来说很直观。
  4. 该机制对于最终用户(他们的登录凭据不会暴露)和开发人员(他们的应用程序凭据不会暴露)都是安全的。
  5. 如果可能,不需要 https(绝不是硬性要求)。

我目前对实施的想法

外部开发人员将请求一个 API 帐户。他们将收到 apikey 和 apisecret。每个请求至少需要三个参数。

  • apikey - 在注册时间戳处提供给开发人员
  • - 兼作给定 apikey
  • 哈希的每条消息的唯一标识符 - 时间戳的哈希 + apisecret

需要 apikey 来识别发出请求的应用程序。时间戳的作用与 oauth_nonce 类似,可以避免/减轻重放攻击。哈希确保请求实际上是由给定 apikey 的所有者发出的。

对于经过身份验证的请求(代表用户完成的请求),我仍然不确定是使用 access_token 路由还是使用用户名和密码哈希组合。无论哪种方式,在某些时候都需要用户名/密码组合。因此,当这样做时,将使用多条信息(apikey、apisecret、时间戳)+密码的哈希值。 我很想得到这方面的反馈。仅供参考,他们必须首先对密码进行哈希处理,因为我不会在没有哈希处理的情况下将密码存储在我的系统中。

结论

仅供参考,这并不是要求如何构建/构建 API,而只是要求如何仅在应用程序内处理身份验证和授权。

随机想法/额外问题

对于仅需要 apikey 作为请求一部分的 API,如何防止 apikey 所有者以外的其他人能够看到 apikey(因为以明文形式发送)并发出过多的请求来推送它们使用限制?也许我只是想得太多了,但是难道不应该有一些东西来验证请求是否已向 apikey 所有者验证吗?就我而言,这就是 apisecret 的目的,它永远不会在未经哈希处理的情况下显示/传输。

说到哈希值,md5 与 hmac-sha1 怎么样?当所有值都使用足够长的数据(即 apisecret)进行哈希处理时,这真的很重要吗?

我之前一直在考虑将每个用户/行的盐添加到我的用户密码哈希中。如果我这样做,应用程序如何能够在不知道所使用的盐的情况下创建匹配的哈希值?

Overview

I'm looking to create a (REST) API for my application. The initial/primary purpose will be for consumption by mobile apps (iPhone, Android, Symbian, etc). I've been looking into different mechanisms for authentication and authorization for web-based APIs (by studying other implementations). I've got my head wrapped around most of the fundamental concepts but am still looking for guidance in a few areas. The last thing I want to do is reinvent the wheel, but I'm not finding any standard solutions that fits my criteria (however my criteria my be misguided so feel free to critique that as well). Additionally, I want the API to be the same for all platforms/applications consuming it.

oAuth

I'll go ahead and throw out my objection to oAuth since I know that will likely be the first solution offered. For mobile applications (or more specifically non-web applications), it just seems wrong to leave the application (to go to a web-browser) for the authentication. Additionally, there is no way (I am aware of) for the browser to return the callback to the application (especially cross-platform). I know a couple of apps that do that, but it just feels wrong and gives a break in the application UX.

Requirements

  1. User enters username/password into application.
  2. Every API call is identified by the calling application.
  3. Overhead is kept to a minimum and the auth aspect is intuitive for developers.
  4. The mechanism is secure for both the end user (their login credentials are not exposed) as well as the developer (their application credentials are not exposed).
  5. If possible, not require https (by no means a hard requirement).

My Current Thoughts on Implementation

An external developer will request an API account. They will receive an apikey and apisecret. Every request will require at minimum three parameters.

  • apikey - given to developer at regisration
  • timestamp - doubles as a unique identifier for each message for a given apikey
  • hash - a hash of the timestamp + the apisecret

The apikey is required to identify the application issuing the request. The timestamp acts similarly to the oauth_nonce and avoids/mitigates replay attacks. The hash ensures that request was actually issued from the owner of the given apikey.

For authenticated requests (ones done on the behalf of a user), I'm still undecided between going with an access_token route or a username and password hash combo. Either way, at some point a username/password combo will be required. So when it does, a hash of several pieces of information (apikey, apisecret, timestamp) + the password would be used. I'd love feedback on this aspect. FYI, they would have to hash the password first, since I don't store the passwords in my system without hashing.

Conclusion

FYI, this isn't a request for how to build/structure the API in general only how to handle the authentication and authorization from solely within an application.

Random Thoughts/Bonus Questions

For APIs that only require an apikey as part of the request, how do you prevent someone other than the apikey owner from being able to see the apikey (since sent in the clear) and make excessive requests to push them over usage limits? Maybe I'm just over thinking this, but shouldn't there be something to authenticate that a request was verified to the apikey owner? In my case, that was the purpose of the apisecret, it is never shown/transmitted without being hashed.

Speaking of hashes, what about md5 vs hmac-sha1? Does it really matter when all of the values are hashed with with sufficiently long data (ie. apisecret)?

I had been previously considering adding a per user/row salt to my users password hash. If I were to do that, how could the application be able to create a matching hash without knowing the salt used?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

怪我闹别瞎闹 2024-10-05 04:43:26

我在项目中考虑执行登录部分的方式是:

  1. 在登录之前,用户从服务器请求一个login_token。这些是根据请求生成并存储在服务器上的,并且可能具有有限的生命周期。

  2. 要登录,应用程序会计算用户密码的哈希值,然后使用 login_token 对密码进行哈希处理以获取值,然后返回 login_token 和组合值

  3. 服务器检查 login_token 是否是它生成的,并将其从有效 login_token 列表中删除。然后,服务器将其存储的用户密码哈希值与 login_token 组合起来,并确保它与提交的组合令牌相匹配。如果匹配,则说明您已经对用户进行了身份验证。

这样做的优点是,您永远不会将用户的密码存储在服务器上,密码永远不会以明文形式传递,密码哈希仅在帐户创建时以明文形式传递(尽管可能有解决方法),并且应该是由于 login_token 在使用时从数据库中删除,因此可以免受重放攻击。

The way I'm thinking about doing the login part of this in my projects is:

  1. before login the user requests a login_token from the server. These are generated and stored on the server on request, and probably have a limited lifetime.

  2. to login the application calculates the hash of the users password, then hashes the password with the login_token to get a value, they then return both the login_token and the combined hash.

  3. The server checks the login_token is one that it has generated, removing it from its list of valid login_tokens. The server then combines its stored hash of the user's password with the login_token and ensures that it matches the submitted combined token. If it matches you have authenticated your user.

Advantages of this are that you never store the user's password on the server, the password is never passed in the clear, the password hash is only passed in the clear on account creation (though there may be ways around this), and it should be safe from replay attacks as the login_token is removed from the DB on use.

挽容 2024-10-05 04:43:26

这是一大堆问题,我猜很多人都没能读完:)

我对 Web 服务身份验证的经验是,人们通常会对其进行过度设计,并且问题仅与您会在网页上遇到。可能非常简单的选项包括用于登录步骤的 https、返回令牌、要求将其包含在未来的请求中。您还可以使用 http 基本身份验证,只需在标头中传递内容即可。为了增加安全性,请经常轮换/使令牌过期,检查请求是否来自同一 IP 块(尽管移动用户在单元之间移动时这可能会变得混乱),并与 API 密钥或类似密钥结合使用。或者,在对用户进行身份验证之前执行 oauth 的“请求密钥”步骤(有人在之前的答案中已经建议了这一点,这是一个好主意),并将其用作生成访问令牌所需的密钥。

我还没有使用过但我听说过很多关于作为 oAuth 的设备友好替代方案的替代方案是 xAuth。看看它,如果你使用它,那么我很想听听你的印象。

对于散列,sha1 更好一点,但不要为此而烦恼 - 无论设备可以轻松(并且在性能意义上快速)实现的任何内容都可能很好。

希望有帮助,祝你好运:)

That's a whole lot of questions in one, I guess quite a few people didn't manage to read all the way to the end :)

My experience of web service authentication is that people usually overengineer it, and the problems are only the same as you would encounter on a web page. Possible very simple options would include https for the login step, return a token, require it to be included with future requests. You could also use http basic authentication, and just pass stuff in the header. For added security, rotate/expire the tokens frequently, check the requests are coming from the same IP block (this could get messy though as mobile users move between cells), combine with API key or similar. Alternatively, do the "request key" step of oauth (someone suggested this in a previous answer already and it's a good idea) before authenticating the user, and use that as a required key to generate the access token.

An alternative which I haven't used yet but I've heard a lot about as a device-friendly alternative to oAuth is xAuth. Have a look at it and if you use it then I'd be really interested to hear what your impressions are.

For hashing, sha1 is a bit better but don't get hung up about it - whatever the devices can easily (and quickly in a performance sense) implement is probably fine.

Hope that helps, good luck :)

幸福不弃 2024-10-05 04:43:26

那么您想要的是某种服务器端身份验证机制来处理移动应用程序的身份验证和授权方面?

假设是这种情况,那么我会按如下方式处理它(但只是因为我是一名 Java 开发人员,所以 C# 人员会采取不同的做法):

RESTful 身份验证和授权服务

  1. 这会起作用仅通过 HTTPS 以防止窃听。
  2. 它将基于 RESTEasySpring SecurityCAS (用于跨多个应用程序的单点登录)。
  3. 它将与浏览器和支持网络的客户端应用程序一起使用
  4. 将有一个基于网络的帐户管理界面,允许用户编辑其详细信息,管理员(针对特定应用程序)可以更改授权级别

客户端安全库/应用程序

  1. 对于每个支持的平台(例如
    Symbian、Android、iOS 等)创建一个
    适当实施
    本地安全库
    平台的语言(例如Java,
    ObjectiveC、C 等)

  2. 应该管理 HTTPS 请求
    使用可用的 API 形成
    对于给定的平台(例如Java
    使用 URLConnection 等)
  3. 一般身份验证的消费者和
    授权库('因为那是
    全部)将编码到特定的
    界面,如果它会不高兴
    不断变化,所以请确保它非常
    灵活的。遵循现有设计
    Spring Security 等选择。

那么现在 30,000 英尺的视图已经完成,您将如何进行呢?嗯,在服务器端使用浏览器客户端创建基于所列出的技术的身份验证和授权系统并不难。与 HTTPS 结合,框架将提供基于身份验证过程生成的共享令牌(通常以 cookie 形式呈现)的安全过程,并在用户希望执行某些操作时使用。每当发生任何请求时,客户端都会向服务器提供此令牌。

对于本地移动应用程序,您似乎需要一个执行以下操作的解决方案:

  1. 客户端应用程序具有定义的访问控制列表 (ACL),控制对方法调用的运行时访问。例如,给定用户可以从方法读取集合,但他们的 ACL 只允许访问名称中带有 Q 的对象,因此集合中的某些数据会被安全拦截器悄悄提取。在 Java 中这很简单,您只需在调用代码上使用 Spring Security 注释并实现合适的 ACL 响应过程即可。在其他语言中,您需要自己提供,并且可能需要提供调用您的安全库的样板安全代码。如果该语言支持 AOP(面向方面​​编程),那么在这种情况下可以充分利用它。
  2. 安全库将完整的授权列表缓存到当前应用程序的私有内存中,以便它不必保持连接。根据登录会话的长度,这可能是一次性操作,永远不会重复。

无论您做什么,不要尝试发明自己的安全协议,或通过默默无闻的方式使用安全性。您永远无法为此编写比当前可用且免费的算法更好的算法。此外,人们信任众所周知的算法。因此,如果您说您的安全库使用 SSL、HTTPS、SpringSecurity 和 AES 加密令牌的组合为本地移动应用程序提供授权和身份验证,那么您将立即在市场上获得信誉。

希望这对您有所帮助,祝您创业顺利。如果您想了解更多信息,请告诉我 - 我已经编写了很多基于 Spring Security、ACL 等的 Web 应用程序。

So what you're after is some kind of server side authentication mechanism that will handle the authentication and authorisation aspects of a mobile application?

Assuming this is the case, then I would approach it as follows (but only 'cos I'm a Java developer so a C# guy would do it differently):

The RESTful authentication and authorisation service

  1. This will work only over HTTPS to prevent eavesdropping.
  2. It will be based on a combination of RESTEasy, Spring Security and CAS (for single sign on across multiple applications).
  3. It will work with both browsers and web-enabled client applications
  4. There will be a web-based account management interface to allow users to edit their details, and admins (for particular applications) to change authorisation levels

The client side security library/application

  1. For each supported platform (e.g.
    Symbian, Android, iOS etc) create a
    suitable implementation of the
    security library in the native
    language of the platform (e.g. Java,
    ObjectiveC, C etc)
  2. The library
    should manage the HTTPS request
    formation using the available APIs
    for the given platform (e.g. Java
    uses URLConnection etc)
  3. Consumers of the general authentication and
    authorisation library ('cos that's
    all it is) will code to a specific
    interface and won't be happy if it
    ever changes so make sure it's very
    flexible. Follow existing design
    choices such as Spring Security.

So now that the view from 30,000ft is complete how do you go about doing it? Well, it's not that hard to create an authentication and authorisation system based on the listed technologies on the server side with a browser client. In combination with HTTPS, the frameworks will provide a secure process based on a shared token (usually presented as a cookie) generated by the authentication process and used whenever the user wishes to do something. This token is presented by the client to the server whenever any request takes place.

In the case of the local mobile application, it seems that you're after a solution that does the following:

  1. Client application has a defined Access Control List (ACL) controlling runtime access to method calls. For example, a given user can read a collection from a method, but their ACL only permits access to objects that have a Q in their name so some data in the collection is quiety pulled by the security interceptor. In Java this is straightforward, you just use the Spring Security annotations on the calling code and implement a suitable ACL response process. In other languages, you're on your own and will probably need to provide boilerplate security code that calls into your security library. If the language supports AOP (Aspect Oriented Programming) then use it to the fullest for this situation.
  2. The security library caches the complete list of authorisations into it's private memory for the current application so that it doesn't have to remain connected. Depending on the length of the login session, this could be a one-off operation that never gets repeated.

Whatever you do, don't try to invent your own security protocol, or use security by obscurity. You'll never be able to write a better algorithm for this than those that are currently available and free. Also, people trust well known algorithms. So if you say that your security library provides authorisation and authentication for local mobile applications using a combination of SSL, HTTPS, SpringSecurity and AES encrypted tokens then you'll immediately have creditibility in the marketplace.

Hope this helps, and good luck with your venture. If you would like more info, let me know - I've written quite a few web applications based on Spring Security, ACLs and the like.

放赐 2024-10-05 04:43:26

Twitter 通过支持名为 xAuth 的变体解决了 oAuth 中的外部应用程序问题。不幸的是,已经有大量其他方案使用这个名称,因此分类起来可能会很混乱。

该协议是 oAuth,只不过它跳过请求令牌阶段,并在收到用户名和密码后立即发出访问令牌对。 (从此处的步骤 E 开始。)此初始请求和响应必须受到保护 - 它以明文形式发送用户名和密码并接收回访问令牌和秘密令牌。配置访问令牌对后,初始令牌交换是通过 oAuth 模型还是 xAuth 模型与会话其余部分的客户端和服务器无关。这样做的优点是您可以利用现有的 oAuth 基础设施,并为移动/网络/桌面应用程序提供几乎相同的实现。主要缺点是应用程序被授予访问客户端用户名和密码的权限,但看起来您的要求强制采用这种方法。

无论如何,我想同意你和其他几个回答者的直觉:不要尝试从头开始构建新的东西。安全协议可能很容易启动,但总是很难做好,而且它们变得越复杂,您的第三方开发人员就越不可能针对它们实施。您的假设协议与 o(x)Auth 非常相似 - api_key/api_secret、nonce、sha1 哈希 - 但您的开发人员将需要推出自己的库,而不是能够使用许多现有库之一。

Twitter addressed the external application issue in oAuth by supporting a variant they call xAuth. Unfortunately there's already a plethora of other schemes with this name so it can be confusing to sort out.

The protocol is oAuth, except it skips the request token phase and simply immediately issues an access token pair upon receipt of a username and password. (Starting at step E here.) This initial request and response must be secured - it's sending the username and password in plaintext and receiving back the access token and secret token. Once the access token pair has been configured, whether the initial token exchange was via the oAuth model or the xAuth model is irrelevant to both the client and server for the rest of the session. This has the advantage that you can leverage existing oAuth infrastructure and have very nearly the same implementation for mobile/web/desktop applications. The main disadvantage is that the application is granted access to the client's user name and password, but it appears like your requirements mandate this approach.

In any case, I'd like to agree with your intuition and that of several other answerers here: don't try to build something new from scratch. Security protocols can be easy to start but are always hard to do well, and the more convoluted they become the less likely your third-party developers are to be able to implement against them. Your hypothetical protocol is very similar to o(x)Auth - api_key/api_secret, nonce, sha1 hashing - but instead of being able to use one of the many existing libraries your developers are going to need to roll their own.

幸福%小乖 2024-10-05 04:43:26

参加聚会已经很晚了,但我想为对此问题感兴趣的任何人提供一些额外的观点。我在一家从事移动 API 安全解决方案的公司工作 (approov),因此整个领域绝对与我的兴趣相关。

首先,在尝试保护移动 API 时要考虑的最重要的事情是它对您的价值。适合银行的正确解决方案不同于适合那些只是为了好玩而做事的人的正确解决方案。

在建议的解决方案中,您提到至少需要三个参数:

  • apikey - 在注册时间戳处提供给开发人员
  • - 兼作给定 apikey
  • 哈希的每条消息的唯一标识符 - 时间戳的哈希 + apisecret

的含义这是因为某些 API 调用不需要用户名/密码。这对于您不想强制登录的应用程序(例如在在线商店中浏览)非常有用。

这是与用户身份验证问题略有不同的问题,更像是软件的身份验证或证明。没有用户,但您仍然希望确保没有人恶意访问您的 API。因此,您可以使用 API 密钥对流量进行签名,并将访问 API 的代码识别为真实代码。此解决方案的潜在问题是您必须泄露应用程序每个版本中的秘密。如果有人可以提取秘密,他们就可以使用您的 API,冒充您的软件,为所欲为。

为了应对这种威胁,您可以采取多种措施,具体取决于数据的价值。 混淆是一种增加秘密提取难度的简单方法。有一些工具可以为您做到这一点,对于 Android 来说更是如此,但您仍然必须拥有生成哈希值的代码,并且技术足够熟练的人始终可以直接调用直接执行哈希值的函数。

缓解过度使用不需要登录的 API 的另一种方法是限制流量并可能识别和阻止可疑 IP 地址。您想要付出的努力很大程度上取决于您的数据的价值。

除此之外,您可以轻松地开始进入我的日常工作领域。不管怎样,这是保护 API 安全的另一个方面,我认为这很重要并且想要标记出来。

Super late to the party but I wanted to throw in some additional points to consider for anyone interested in this issue. I work for a company doing mobile API security solutions (approov) so this whole area is definitely relevant to my interests.

To start with, the most important thing to consider when trying to secure a mobile API is how much it is worth to you. The right solution for a bank is different to the right solution for someone just doing things for fun.

In the proposed solution you mention that a minimum of three parameters will be required:

  • apikey - given to developer at registration
  • timestamp - doubles as a unique identifier for each message for a given apikey
  • hash - a hash of the timestamp + the apisecret

The implication of this is that for some API calls no username/password is required. This can be useful for applications where you don't want to force a login (browsing in online shops for example).

This is a slightly different problem to the one of user authentication and is more like authentication or attestation of the software. There is no user, but you still want to ensure that there is no malicious access to your API. So you use your API secret to sign the traffic and identify the code accessing the API as genuine. The potential problem with this solution is that you then have to give away the secret inside every version of the app. If someone can extract the secret they can use your API, impersonating your software but doing whatever they like.

To counter that threat there are a bunch of things you can do depending on how valuable the data is. Obfuscation is a simple way to make it harder to extract the secret. There are tools that will do that for you, more so for Android, but you still have to have code that generates your hash and a sufficiently skilled individual can always just call the function that does the hashing directly.

Another way to mitigate against excessive use of an API that doesn't require a login is to throttle the traffic and potentially identify and block suspect IP addresses. The amount of effort you want to go to will largely depend upon how valuble your data is.

Beyond that you can easily start getting into the domain of my day job. Anyway, it's another aspect of securing APIs that I think is important and wanted to flag up.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文