1. 程式人生 > 其它 >使用阿里雲sts鑑權模式實踐(php),拋去複雜的官方sdk,自由裸奔

使用阿里雲sts鑑權模式實踐(php),拋去複雜的官方sdk,自由裸奔

技術標籤:php

背景

因為最近需要遇到客戶端直接使用hackCode方式引入子賬號,存在賬號洩露問題,遂尋找一種對客戶端影響較少也能保證賬號安全的解決方法,所以就有了本文。

關於STS

  1. 阿里雲 STS(Security Token Service)是阿里雲提供的一種臨時訪問許可權管理服務。
  2. 通過 STS 服務,您所授權的身份主體(RAM 使用者、RAM 使用者組或 RAM 角色)可以獲取一個自定義時效和訪問許可權的臨時訪問令牌。STS令牌持有者可以通過以下方式訪問阿里雲資源:
    • 通過程式設計方式訪問被授權的阿里雲服務 API。
    • 登入阿里雲控制檯操作被授權的雲資源。
      *RAM (Resource Access Management) 是阿里云為客戶提供的使用者身份管理與資源訪問控制服務。

為什麼要使用RAM和STS

  1. RAM和STS需要解決的一個核心問題是如何在不暴露主賬號的AccessKey的情況下安全的授權別人訪問。因為一旦主賬號的AccessKey暴露出去的話會帶來極大的安全風險,別人可以隨意操作該賬號下所有的資源,盜取重要資訊等。
  2. RAM提供一種長期有效的許可權控制機制,通過分出不同許可權的子賬號,將不同的許可權分給不同的使用者,這樣一旦子賬號洩露也不會造成全域性的資訊洩露。但是,由於子賬號在一般情況下是長期有效的,因此,子賬號的AccessKey也是不能洩露的。
  3. 相對於RAM提供的長效控制機制,STS提供的是一種臨時訪問授權。通過STS可以返回臨時的AccessKey和Token,這些資訊可以直接發給臨時使用者用來訪問OSS/VOD服務等。一般來說,從STS獲取的許可權會受到更加嚴格的限制,並且擁有時間限制,因此這些資訊洩露之後對於系統的影響也很小。

STS 訪問點

用於 API 訪問的 STS 接入點:https://sts.aliyuncs.com。

STS 術語表

術語說明
RAM Role一種虛擬的RAM使用者。
Role ArnRole ARN 是角色的全域性資源描述符,用來指定具體角色。每個角色都有一個唯一的全域性資源描述符。格式:acs:ram::$accountID:role/$roleName
Trusted Entity角色的受信主體是指可以扮演角色的實體使用者身份。建立角色時必須指定受信主體,角色只能被受信的主體扮演。受信主體可以是受信的阿里云云賬號,或者受信阿里雲服務。
Assume Role扮演角色是實體使用者獲取角色身份的安全令牌的方法。一個實體使用者通過呼叫 AssumeRole 的 API 可以獲得角色的安全令牌,使用安全令牌可以訪問雲服務 API。

STS鑑權模式

OSS可以通過阿里雲STS (Security Token Service) 進行臨時授權訪問。阿里雲STS是為雲端計算使用者提供臨時訪問令牌的Web服務。通過STS,您可以為第三方應用或子使用者(即使用者身份由您自己管理的使用者)頒發一個自定義時效和許可權的訪問憑證。
STS鑑權模式具有以下優勢:

  • 無需透露您的長期金鑰(AccessKey)給第三方應用,只需生成一個訪問令牌並將令牌交給第三方應用。您可以自定義這個令牌的訪問許可權及有效期限。
  • 無需關心許可權撤銷問題,訪問令牌過期後訪問許可權會自動失效。

以APP應用為例,互動流程如圖所示(來自阿里雲官方文件):

以上(來自阿里雲文件)只是為讓大家先對STS有初步的瞭解,以及應用場景,下面進入正題

--------------------------------分割線-----------------------------

如何通過STS獲取安全令牌呢?

1.先上程式碼

class STS
{
    protected $url = 'https://sts.aliyuncs.com';
    protected $accessKeySecret = '1234567890qwertyuioasdfghj';
    protected $accessKeyId = 'LT11234567898';
    protected $roleArn = 'acs:ram::$accountID:role/$roleName';//指定角色的 ARN ,角色策略許可權
    protected $roleSessionName = 'client1';//使用者自定義引數。此引數用來區分不同的 token,可用於使用者級別的訪問審計。格式:^[a-zA-Z0-9\[email protected]\-_]+$
    protected $durationSeconds = '1800';//指定的過期時間
    protected $type = 'xxx';//方便呼叫時獲取不同的許可權

    public function __construct($type)
    {
        $this->type = $type;
        $this->setRoleArn();
    }

    public function sts()
    {
        $action = 'AssumeRole';//通過扮演角色介面獲取令牌
        date_default_timezone_set('UTC');
        $param = array(
            'Format'           => 'JSON',
            'Version'          => '2015-04-01',
            'AccessKeyId'      => $this->accessKeyId,
            'SignatureMethod'  => 'HMAC-SHA1',
            'SignatureVersion' => '1.0',
            'SignatureNonce'   => $this->getRandChar(8),
            'Action'           => $action,
            'RoleArn'          => $this->roleArn,
            'RoleSessionName'  => $this->roleSessionName,
            'DurationSeconds'  => $this->durationSeconds,
            'Timestamp'        => date('Y-m-d') . 'T' . date('H:i:s') . 'Z'
            //'Policy'=>'' //此引數可以限制生成的 STS token 的許可權,若不指定則返回的 token 擁有指定角色的所有許可權。
        );
        $param['Signature'] = $this->computeSignature($param, 'POST');
        $res = CurlHandle::httpPost($this->url, $param);//curl post請求
        if ($res) {
            return self::_render($res);
        } else {
            return [];
        }
    }

    private static function _render($res)
    {
        $res = json_decode($res, true);
        if (empty($res['Credentials'])) {
            return [];
        } else {
            return [
                'accessKeySecret' => $res['Credentials']['AccessKeySecret'] ?? '',
                'accessKeyId'     => $res['Credentials']['AccessKeyId'] ?? '',
                'expiration'      => $res['Credentials']['Expiration'] ?? '',
                'securityToken'   => $res['Credentials']['SecurityToken'] ?? '',
            ];
        }
    }

    protected function computeSignature($parameters, $setMethod)
    {
        ksort($parameters);
        $canonicalizedQueryString = '';
        foreach ($parameters as $key => $value) {
            $canonicalizedQueryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($value);
        }
        $stringToSign = $setMethod . '&%2F&' . $this->percentencode(substr($canonicalizedQueryString, 1));
        $signature = $this->getSignature($stringToSign, $this->accessKeySecret . '&');

        return $signature;
    }

    public function getSignature($source, $accessSecret)
    {
        return base64_encode(hash_hmac('sha1', $source, $accessSecret, true));
    }

    protected function percentEncode($str)
    {
        $res = urlencode($str);
        $res = preg_replace('/\+/', '%20', $res);
        $res = preg_replace('/\*/', '%2A', $res);
        $res = preg_replace('/%7E/', '~', $res);
        return $res;
    }

    public function getRandChar($length)
    {
        $str = null;
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($strPol) - 1;

        for ($i = 0; $i < $length; $i++) {
            $str .= $strPol[rand(0, $max)];//rand($min,$max)生成介於min和max兩個數之間的一個隨機整數
        }

        return $str;
    }

    protected function setRoleArn()
    {
        if ($this->type == '123') {//根據入參使用不同的策略,當然這裡還可以有其他寫法相容更多的策略的情況
            $this->roleArn = 'acs:ram::123456789098:role/=$roleName';
        }
    }
}

2.返回結果

{
    "Credentials": {
        "AccessKeyId": "STS.xxxxxxxxxxxxx****",//訪問金鑰標識
        "AccessKeySecret": "xxxxxxxxxx****",//訪問金鑰
        "Expiration": "2019-04-09T11:52:19Z",//失效時間
        "SecurityToken": "********"//安全令牌
    },
    "AssumedRoleUser": {
        "arn": "acs:sts::123456765456****:assumed-role/AdminRole/client",
        "AssumedRoleUserId":"1234567121****:alice"
        },
    "RequestId": "xxxxxxxxxxxxxxxx"
}

相信大家看完前面的解析、程式碼及返回結果後大概對怎麼使用STS鑑權模式有一定了解;返回結果中對於客戶端APP來講需要用的有AccessKeyId、AccessKeySecret、Expiration、SecurityToken,客戶端拿到這四個引數後將其傳給阿里雲ossSDK,vodSDK等便可以正常使用oss上傳服務或者短視訊vod服務了。

使用STS鑑權具體步驟

  1. 在阿里雲後臺開通一個RAM子賬號
  2. 新建角色(表示某種操作許可權),授權相應的策略
  3. 通過呼叫STS的AssumeRole介面,傳遞RAM子賬號的AccessKeyId、AccessKeySecret以及指定角色的 ARN ,角色策略許可權 roleArn 獲取臨時授權

    AccessKeyId": "STS.xxxxxxxxxxxxx****",//訪問金鑰標識
    "AccessKeySecret": "xxxxxxxxxx****",//訪問金鑰
    "Expiration": "2019-04-09T11:52:19Z",//失效時間
    "SecurityToken": "********"//安全令牌
    

  4. 然後…emmm…把想法寫成程式碼邏輯。

  5. 附:阿里雲對RAM和STS具體介紹文件地址:https://help.aliyun.com/document_detail/31931.html?spm=a2c4g.11186623.2.10.34c51388aBbFjR#concept-nsb-brz-5db