使用签名的 Cookies
当我将 CloudFront 与许多私有 URL 一起使用时,我更喜欢在满足所有 restrictions 时使用 Signed Cookies。这不会加快签名 cookie 的生成速度,但会将签名请求的数量减少到每个用户一个,直到它们过期。
调整 RSA 签名生成
我可以想象您可能有将签名 cookie 呈现为无效选项的要求。在这种情况下,我尝试通过比较与 boto 和 cryptography 一起使用的 RSA 模块来加快签名速度。另外两个替代选项是m2crypto 和pycrypto,但对于本例,我将使用密码学。
为了测试使用不同模块对 URL 进行签名的性能,我减少了 _sign_string 方法以删除除字符串签名之外的任何逻辑,然后创建了一个新的 Distribution 类。然后我从boto tests 获取私钥和示例 URL 进行测试。
结果表明,加密速度更快,但每个签名请求仍需要接近 1 毫秒。这些结果因 iPython 在时序中使用范围变量而产生了更高的偏差。
timeit -n10000 rsa_distribution.create_signed_url(url, message, expire_time)
10000 loops, best of 3: 6.01 ms per loop
timeit -n10000 cryptography_distribution.create_signed_url(url, message, expire_time)
10000 loops, best of 3: 644 µs per loop
完整的脚本:
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
import rsa
from boto.cloudfront.distribution import Distribution
from textwrap import dedent
# The private key provided in the Boto tests
pk_key = dedent("""
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDA7ki9gI/lRygIoOjV1yymgx6FYFlzJ+z1ATMaLo57nL57AavW
hb68HYY8EA0GJU9xQdMVaHBogF3eiCWYXSUZCWM/+M5+ZcdQraRRScucmn6g4EvY
2K4W2pxbqH8vmUikPxir41EeBPLjMOzKvbzzQy9e/zzIQVREKSp/7y1mywIDAQAB
AoGABc7mp7XYHynuPZxChjWNJZIq+A73gm0ASDv6At7F8Vi9r0xUlQe/v0AQS3yc
N8QlyR4XMbzMLYk3yjxFDXo4ZKQtOGzLGteCU2srANiLv26/imXA8FVidZftTAtL
viWQZBVPTeYIA69ATUYPEq0a5u5wjGyUOij9OWyuy01mbPkCQQDluYoNpPOekQ0Z
WrPgJ5rxc8f6zG37ZVoDBiexqtVShIF5W3xYuWhW5kYb0hliYfkq15cS7t9m95h3
1QJf/xI/AkEA1v9l/WN1a1N3rOK4VGoCokx7kR2SyTMSbZgF9IWJNOugR/WZw7HT
njipO3c9dy1Ms9pUKwUF46d7049ck8HwdQJARgrSKuLWXMyBH+/l1Dx/I4tXuAJI
rlPyo+VmiOc7b5NzHptkSHEPfR9s1OK0VqjknclqCJ3Ig86OMEtEFBzjZQJBAKYz
470hcPkaGk7tKYAgP48FvxRsnzeooptURW5E+M+PQ2W9iDPPOX9739+Xi02hGEWF
B0IGbQoTRFdE4VVcPK0CQQCeS84lODlC0Y2BZv2JxW3Osv/WkUQ4dslfAQl1T303
7uwwr7XTroMv8dIFQIPreoPhRKmd/SbJzbiKfS/4QDhU
-----END RSA PRIVATE KEY-----""")
# Initializing keys in a global context
cryptography_private_key = serialization.load_pem_private_key(
pk_key,
password=None,
backend=default_backend())
# Instantiate a signer object using PKCS 1v 15, this is not recommended but required for Amazon
def sign_with_cryptography(message):
signer = cryptography_private_key.signer(
padding.PKCS1v15(),
hashes.SHA1())
signer.update(message)
return signer.finalize()
# Initializing the key in a global context
rsa_private_key = rsa.PrivateKey.load_pkcs1(pk_key)
def sign_with_rsa(message):
signature = rsa.sign(str(message), rsa_private_key, 'SHA-1')
return signature
# All this information comes from the Boto tests.
url = "http://d604721fxaaqy9.cloudfront.net/horizon.jpg?large=yes&license=yes"
expected_url = "http://d604721fxaaqy9.cloudfront.net/horizon.jpg?large=yes&license=yes&Expires=1258237200&Signature=Nql641NHEUkUaXQHZINK1FZ~SYeUSoBJMxjdgqrzIdzV2gyEXPDNv0pYdWJkflDKJ3xIu7lbwRpSkG98NBlgPi4ZJpRRnVX4kXAJK6tdNx6FucDB7OVqzcxkxHsGFd8VCG1BkC-Afh9~lOCMIYHIaiOB6~5jt9w2EOwi6sIIqrg_&Key-Pair-Id=PK123456789754"
message = "PK123456789754"
expire_time = 1258237200
class CryptographyDistribution(Distribution):
def _sign_string(
self,
message,
private_key_file=None,
private_key_string=None):
return sign_with_cryptography(message)
class RSADistribution(Distribution):
def _sign_string(
self,
message,
private_key_file=None,
private_key_string=None):
return sign_with_rsa(message)
cryptography_distribution = CryptographyDistribution()
rsa_distribution = RSADistribution()
cryptography_url = cryptography_distribution.create_signed_url(
url,
message,
expire_time)
rsa_url = rsa_distribution.create_signed_url(
url,
message,
expire_time)
assert cryptography_url == rsa_url == expected_url, "URLs do not match"
结论
虽然加密模块在此测试中表现更好,但我建议尝试找到一种利用签名 cookie 的方法,但我希望这些信息有用。