如何控制外部网站访问我的Web服务?

时间:2012-04-04 09:35:57

标签: php web-services security

* 我正在尝试找出如何实现“最简单”的身份识别形式,以便我的合作伙伴网站访问我的网络服务以检索信息。 *

我想确保只有我的合作伙伴才有权检索此信息。由于数据将显示在我的合作伙伴网站上,因此没有敏感数据。但我不希望其他网站利用我的网络服务并在没有访问权限的情况下检索数据。

我知道我可以使用HttpRequest object获取IP地址,然后进行反向查找。但并非所有网站都有专用的IP地址,ISP可能会为多个网站使用相同的IP地址。

我无法看到如何在URL中传递唯一标识符作为参数可以提供帮助,因为“任何人”都可以捕获该数据并自行使用它。但我会将它作为额外的支票使用。

因此,我提出的唯一“安全”方式是识别访问我网站的网站,然后根据我服务器上的列表进行控制。

我希望得到关于哪种方法“最安全”的反馈。

2 个答案:

答案 0 :(得分:2)

最安全的方法是使用SSL通道并请求身份验证。如果身份验证通过,那么您可以向客户端返回某种会话密钥(可以是随机生成的字符串),并在每次请求时检查它。

如果您的服务不允许使用SSL,那么您可以尝试为合作伙伴添加简单的用户名/密码身份验证,但在这种情况下,如果有人拦截您的通信,他们可以使用相同的凭据访问您的服务。

其他方式是在每个请求上使用签名。例如,您可以将GPG用于此目的。您的服务器正在保存所有合作伙伴的公钥。当合作伙伴想要对您的服务器进行查询时,他只需使用他的私钥签署他的请求,一旦收到您,您将能够安全地验证此请求是由特定合作伙伴发送的,并且100%不是伪造的。

修改

对于GPG,您需要安装名为gnupg的PECL模块。以下是我们的框架中使用GPG功能的类。

class GPG
{

    /**
     * Encrypt given data to one or more recipients
     * 
     * @param string $string
     * @param string|array $encryptKeyID
     * @param bollean $armour
     * @return string
     */
    public static function encrypt($string, $encryptKeyID, $armour = true){
        $gpg = new Crypt_GPG();

        if(is_array($encryptKeyID)){
            foreach($encryptKeyID as $keyId){
                $gpg->addEncryptKey($keyId);
            }
        }
        else{
            $gpg->addEncryptKey($encryptKeyID);
        }

        return $gpg->encrypt($string, $armour);
    }

    /**
     * Decrypt given data
     *  
     * @param string $string
     * @param string $keyPassword
     * @param string $keyID
     * @return string
     */
    public static function decrypt($string, $keyID, $keyPassword = null){
        $gpg = new Crypt_GPG();

        $gpg->addDecryptKey($keyID, $keyPassword);

        return $gpg->decrypt($string);
    }

    /**
     * Sign given string
     * 
     * @param string $string
     * @param string $keyID
     * @param string $keyPassword
     * @param boolean $mode
     * @param boolean $armor
     * @return string
     */
    public static function sign($string, $keyID, $keyPassword = null, $mode = null, $armor = true){
        $gpg = new Crypt_GPG();

        if($mode === null){
            $mode = Crypt_GPG::SIGN_MODE_CLEAR;
        }

        $gpg->addSignKey($keyID, $keyPassword);

        return $gpg->sign($string, $mode);
    }

    /**
     * Verify signature of given message
     * 
     * @param string $string
     * @return boolean
     */
    public static function verify($string){
        $gpg = new Crypt_GPG();
        $signatures = $gpg->verify($string);

        if ($signatures[0]->isValid()) {
            return true;
        } 
        else{
            return false;
        }
    }

    /**
     * Encrypt and sign given string to one or more recipients
     * 
     * @param string $string
     * @param string|array $encryptKeyID
     * @param string $signkeyID
     * @param string $signkeyPassword
     * @param boolean $mode
     * @param boolean $armor
     * @return string
     */
    public static function encryptAndSign($string, $encryptKeyID, $signkeyID, $signkeyPassword = null, $mode = null, $armor = true){
        $gpg = new Crypt_GPG();

        if($mode === null){
            $mode = Crypt_GPG::SIGN_MODE_CLEAR;
        }

        $gpg->addSignKey($signkeyID, $signkeyPassword);
        if(is_array($encryptKeyID)){
            foreach($encryptKeyID as $keyId){
                $gpg->addEncryptKey($keyId);
            }
        }
        else{
            $gpg->addEncryptKey($encryptKeyID);
        }

        return $gpg->encryptAndSign($string, $armor);
    }

    /**
     * Decrypt and verify given string
     * 
     * @param string $string
     * @param string $keyID
     * @param string $keyPassword
     * @return array|false
     */
    public static function decryptAndVerify($string, $keyID, $keyPassword = null){
        $gpg = new Crypt_GPG();

        $gpg->addDecryptKey($keyID, $keyPassword);

        $result = $gpg->decryptAndVerify($string);

        if(empty($result['data']) and empty($result['signatures'])){
            return false;
        }

        if(isset($result['signatures'][0])){
            $result['signature'] = $result['signatures'][0]->isValid();
            unset($result['signatures']);
        }

        return $result;
    }
} 

答案 1 :(得分:2)

Web服务中通常使用公钥/私钥来验证API请求。一些使用它们的示例网站:Google,Twitter,EventBriteLast.FM,GitHub等。

这些工作通过拥有众所周知的公共或消费者密钥来实现。然后为每个用户提供私钥或密钥以允许身份验证。使用它的一个很酷的事情是,因为你确切地知道谁在提出请求,你有能力跟踪活动并可能在被滥用时限制请求数量。