保护可从Android访问的REST API

我们正在构建一款Android游戏,需要访问Web服务 – 因此我们在PHP中编写了一个RESTful API,它在我们自己的服务器上运行。 API提供的是: 创建用户,登录,下载游戏,检索游戏列表,提交分数等等。现在我想,如果一些有经验的用户获得API的URL格式 – 他/他将能够以多种方式废弃系统:

  • 创建一个脚本并运行它来创建自动用户 – 我想我可以通过CAPTCHA或类似的东西来阻止它。 但同样,validation码会惹恼游戏玩家。
  • 恶意用户使用他的浏览器登录,下载游戏然后按照自己的意愿提交分数 – 所有这一切都可以通过简单地从浏览器中输入来调用API。 我假设恶意用户以某种方式知道要调用的API URL – 通过在应用程序发出HTTP请求时嗅探。
  • 我需要确保仅从安装游戏的Android设备发出请求。 (游戏将免费)

现在我该如何防止这种滥用?

我认为你永远无法隐藏应用程序调用的URL(如果我运行的是ro​​ot用户手机,我应该可以监视所有网络流量)

但你真正的问题是你需要以某种方式validation你的api。

一种方法是实施OAUTH,但也许这有点过分。

如果你想要一个简单的机制,那怎么样;

  1. 创建一个密钥
  2. 构建api请求(例如https://my.example.com/users/23?fields=name,email )
  3. 哈希此请求路径+加上您的密钥(例如.md5(url + secret_key)==“a3c2fe167”)
  4. 将此哈希添加到您的请求中(现在它是https:// …..? fields = name,email&hash = a3c2fe167 )
  5. 在api端,执行相同的转换(删除哈希参数)
  6. 检查url的md5和密钥

只要秘密保密,没有人可以伪造你的要求。

示例(伪代码):

Android方面:

SECRET_KEY = "abc123" def call_api_with_secret(url, params) # create the hash to sign the request hash = MD5.hash(SECRET_KEY, url, params) # call the api with the added hash call_api(url+"&hash=#{hash}", params) end 

服务器端:

 SECRET_KEY = "abc123" def receive_from_api(url, params) # retrieve the hash url_without_hash, received_hash = retrieve_and_remove_hash(url) # check the hash expected_hash = MD5.hash(SECRET_KEY, url_without_hash, params) if (expected_hash != received_hash) raise our exception! end # now do the usual stuff end 

其他人在这里介绍的解决方案通过默默无闻称为安全性 。 基本上他们试图模糊协议并隐藏实现。 这可能会有效,直到有足够能力拆卸应用程序并对协议进行逆向工程。 黑客非常有能力做到这一点。

问题是你的应用程序是否值得破解? 像iTunes,DVD或索尼PS3网络这样的计划显然是值得的。 如果没有人能够解决问题,那么默默无闻的方法可能会奏效。 只是不要欺骗自己,这是不可行的。

由于您无法信任该设备或您的应用,因此您必须信任该用户。 为了信任用户,您需要用户识别和授权系统。 基本上是您的应用程序的登录。 而是滚动你自己的识别系统(登录确认电子邮件等),使用第三方系统:OpenID(谷歌帐户)或OAuth(Facebook,推特)。 如果Facebook使用服务器端身份validation方案。

我要做的是:

  1. 允许用户自由玩游戏,直到他们想要在服务器上“保存”结果。
  2. 在保存结果之前,让他们通过上述方法登录。
  3. 使用HTTPS将数据发送到服务器。 从受信任的CA购买ssl证书,因此您无需处理自签名证书。

你提到用户伪造高分。 如果您的用户经过身份validation,这仍可能发生。 当游戏上传高分时,您可能希望它也上传分数certificate。 例如,得分20100从103个虫子挤压,飞行1200英里,达到3级,吃掉2个樱桃。 这绝不是完美的,但会涵盖低悬的果实。

您应该做的第一件事是经过身份validation的用户。 用户ID /密码/会话令牌等,看看你是否能find一些已经存在的框架。 一旦您拥有用户身份validation,请确保您可以使用TLS或类似function安全地执行此操作。

据我所知,您的服务器无法确定请求是来自您的应用程序(它只是数据包中的位),但您至少可以让某人变得很难恶意。

  • 在您的应用程序中构建一个秘密(如其他响应,密钥,哈希盐等所示)
  • 安装后首次执行应用程序时生成唯一ID,并跟踪登录用户。 有关此内容的详细信息以及设备的唯一ID(为什么不使用它)可以在Android博客上find
  • 本文中讨论的一些想法如何确保/确定post来自在iPhone / iTouch上运行的特定应用程序?
  • 检查用户代理

如果您确实想要保护连接,那么您将不得不使用公钥加密技术,例如RSA。 设备将使用公钥加密登录信息,在服务器端,您必须使用私钥解密。 登录后,服务器将发送令牌/加密密钥(响应将是加密的JSON或其他东西),设备将存储该密钥。 从那时起,只要会话未到期,设备就会发送使用该令牌加密的所有信息。 对于此请求,您不应使用需要更多时间的RSA原因。 您可以使用AES256(这是一种流行的私钥加密)与从服务器接收的加密密钥来加密您的请求。

为简单起见,您可以完全放弃RSA(如果您不发送付款信息)并使用带私钥的AES256执行所有操作。 步骤应该是 –

  • 使用私钥加密每个传出请求。
  • 将加密的字符串转换为base 64字符串。
  • URL编码基本64编码的字符串。
  • 发送过来。

在服务器端

  • 做base 64解码
  • 使用私钥解密。

您的请求应带有签名(例如,附加为盐的加密密钥),以便在解密后识别它。 如果签名不存在,则只需丢弃该请求。

对于发送响应也这样做。

Android SDK应具有使用AES256和Base 64编码进行加密的方法。

通过使用通过Google API提供的Oauth令牌,遵循Android团队的这些指南来保护您的后端。