Php 保护可从Android访问的REST API

Php 保护可从Android访问的REST API,php,android,security,rest,Php,Android,Security,Rest,我们正在为Android构建一个需要访问web服务的游戏,所以我们用PHP编写了一个RESTful API,在我们自己的服务器上运行。API提供的功能是:创建用户、登录、下载游戏、检索游戏列表、提交分数。。。等等。现在我在想,如果某个有经验的用户获得API的URL格式,他将能够以多种方式破坏系统: 创建一个脚本并运行它来创建自动用户-我想我可以通过验证码或类似的东西来阻止它。但同样,验证码会惹恼游戏玩家 恶意用户使用浏览器登录,下载游戏,然后根据自己的意愿提交分数——所有这些都是通过调用API

我们正在为Android构建一个需要访问web服务的游戏,所以我们用PHP编写了一个RESTful API,在我们自己的服务器上运行。API提供的功能是:创建用户、登录、下载游戏、检索游戏列表、提交分数。。。等等。现在我在想,如果某个有经验的用户获得API的URL格式,他将能够以多种方式破坏系统:

  • 创建一个脚本并运行它来创建自动用户-我想我可以通过验证码或类似的东西来阻止它。但同样,验证码会惹恼游戏玩家
  • 恶意用户使用浏览器登录,下载游戏,然后根据自己的意愿提交分数——所有这些都是通过调用API,只需在浏览器中键入即可完成的。我假设恶意用户在应用程序发出HTTP请求时通过嗅探知道要调用的API URL
  • 我需要确保请求只来自安装游戏的Android设备。(游戏免费)

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

我认为您永远无法隐藏应用程序调用的URL (如果我运行的是root-ed安卓手机,我应该能够监视所有网络流量)

但真正的问题是,您需要以某种方式对api进行身份验证

一种方法是实现OAUTH,但这可能有点过头了

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

  • 创建密钥
  • 构建api请求(例如)
  • 散列此请求路径+加上您的密钥(例如md5(url+密钥)=“a3c2fe167”)
  • 将此哈希添加到您的请求中(现在是)
  • 在api端,执行相同的转换(删除hash参数)
  • 检查url的md5和密钥
  • 只要秘密仍然是秘密,没有人能伪造你的请求

    示例(伪代码):

    安卓端:

    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
    

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

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

    • 使用私钥加密每个传出请求
    • 将加密字符串转换为基64字符串
    • URL编码基64编码字符串
    • 把它送来
    在服务器端

    • 基本64解码吗
    • 使用私钥解密
    您的请求应该带有签名(例如,加密密钥附加为salt),以便在解密后能够识别它。如果签名不存在,只需放弃请求即可

    对于发送响应,请执行相同的操作


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

    您提到过伪造高分的用户。如果您的用户经过身份验证,这种情况仍然可能发生。当游戏上传高分时,你可能想让它也上传分数证明。例如,103只虫子被压扁,飞行1200英里,达到3级,吃了2颗樱桃,得到了20100分。这绝不是完美的,但可以覆盖低垂的果实

    首先应该让经过身份验证的用户。Userid/password/sessiontoken等,看看是否可以找到一些已经存在的框架。一旦您进行了用户身份验证,请确保您可以使用TLS或类似工具安全地进行验证

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