Я работаю на канале Roku, и мы хотим, чтобы файлы размещались в корзине AWS S3 с CloudFront для распространения контента. Прежде чем рассматривать безопасность, он работал нормально. Однако теперь, когда я пытаюсь помнить о проблемах безопасности, у меня возникают проблемы. У меня есть корзина S3 как частная корзина (в ней нет открытого доступа к чему-либо), и я создал исходный идентификатор доступа для дистрибутива CloudFront, чтобы он мог получить доступ к содержимому корзины.
Проблема в том, что я не могу создать устаревшие подписанные URL-адреса (или файлы cookie) в коде brightscript канала, чтобы получить доступ к контенту. Я могу создать подписанный URL-адрес с помощью сценария Amazon perl через командную строку, и если я скопирую / вставлю часть подписи ссылки, она выдаст меня в часть подписи URL-адреса, который я создаю в brightscript (заменяя подпись) это работает. Конечно, это потому, что все остальное в URL-адресах идентично, поэтому после замены подписи у меня просто остается другой URL-адрес. Так что я знаю (по крайней мере, я думаю, что могу с уверенностью сказать), что проблема с подписью. Я выполняю действия, указанные в документации AWS , но она всегда возвращается с сообщением об ошибке «Отказано в доступе».
Единственная часть процесса подписи, которую я пропустил, - это кодировка base 64. Я пробовал base 64, кодирующую подпись, которую создает brightscript, используя этот сайт и обновляя URL и пробуя его, но все же не повезло. Я чувствую, что это как-то связано с тем, как brightscript хэширует или подписывает вещи. В сообщении Stack Overflow я видел, что openssl (то, что сценарий perl использует для хеширования / подписи) также кодирует в ASN.1 перед подписанием ... Я пытался с этим поработать, чтобы увидеть если бы я мог заставить его работать, включая этот шаг, но мне тоже не повезло.
Может быть, я не делаю это правильно, или, может быть, это не проблема. Я знаю, что некоторые люди используют S3 и CloudFront для размещения контента для каналов Roku, поэтому я не знаю, почему он не должен работать. Надеюсь, кто-то там может пролить немного света ... Если кто-то знает решение, я был бы рад услышать его!
Edit:
Я понял, что способ преобразования байтового массива в строку был НЕПРАВИЛЬНЫМ! Я изменил это из этого:
//To convert from byteArray to string
signatureString = ""
for each byte in signature
signatureString = signatureString + stri(byte)
end for
на это:
sigString = signature.ToAsciiString()
print "sigString: ";sigString
signatureString = signature.ToBase64String()
К сожалению, мне все еще отказывают в доступе. Однако, по крайней мере, теперь мои URL выглядят как URL, которые создает скрипт perl - до того, как часть подписи была просто набором цифр. Кроме того, теперь я использую кодировку подписи base 64. Я чувствую, что могу быть ближе! :)
Редактировать 2: У меня есть открытая тема на форумах Roku с небольшой активностью: https://forums.roku.com/viewtopic.php?t=54797
Я обнаружил, что строка политики была неправильной - у нее было «Condition» перед «Resource» (в результате анализа JSON из roAssociativeArray). Мне удалось получить правильную строку политики, но я все равно получаю отказ в доступе.
Вот код, который я использую для создания подписанного URL:
readInternet = createObject("roUrlTransfer")
policy = { "Statement": [
{
"Resource":"http://XXXXXXXXXXXXX.cloudfront.net/icon_focus_sd.png",
"Condition": {
"DateLessThan": {
"AWS:EpochTime": 1561230905
}
}
}
]
}
policyString = FormatJson(policy)
print "policyString: ";policyString
//UPDATE: correct policy string now:
policyString = "{" + Chr(34) + "Statement" + Chr(34) + ":[{" + Chr(34) + "Resource" + Chr(34) + ":" + Chr(34) + "http://d1uuhuldzrqhow.cloudfront.net/icon_focus_sd.png" + Chr(34) + "," + Chr(34) + "Condition" + Chr(34) + ":{" + Chr(34) + "DateLessThan" + Chr(34) + ":{" + Chr(34) + "AWS:EpochTime" + Chr(34) + ":1561230905}}}]}"
ba.FromAsciiString(policyString)
print "New policy string: ";policyString
ba = CreateObject("roByteArray")
ba.FromAsciiString(policyString)
digest = CreateObject("roEVPDigest")
digest.Setup("sha1")
hashString = digest.Process(ba)
print "hashString: ";hashString
hashBA = CreateObject("roByteArray")
hashBA.FromHexString(hashString)
rsa = CreateObject("roRSA")
rsa.setPrivateKey("pkg:/components/key/privateKey.pem")
rsa.SetDigestAlgorithm("sha1")
signature = rsa.Sign(hashBA)
//EDIT! The following 3 lines are a big development!
sigString = signature.ToAsciiString()
print "sigString: ";sigString
signatureString = signature.ToBase64String()
//To convert from byteArray to string --Commented this part out as it was WRONG!!!
//signatureString = ""
//for each byte in signature
// signatureString = signatureString + stri(byte)
//end for
print "Signature: ";signature
print "SignatureString: ";signatureString
baseURL = policy.statement[0].resource
print "BaseURL: ";baseURL
fixedSignatureString = signatureString.replace(" ", "").replace("=", "_").replace("/", "~").replace("+", "-")
dateKeys = policy.statement[0].condition.datelessthan.Keys()
print"dateKeys: ";dateKeys
print"dateKey: ";dateKeys[0]
epochTime = policy.statement[0].condition.dateLessThan.Lookup(dateKeys[0])
finalURL = baseURL + "?Expires=" + stri(epochTime).Replace(" ","") + "&Signature=" + fixedSignatureString + "&Key-Pair-Id=APKXXXXXXXXXXVWQ"
print "finalURL: ";finalURL
readInternet.setUrl(finalURL)
readInternet.SetCertificatesFile("common:/certs/ca-bundle.crt")
readInternet.AddHeader("X-Roku-Reserved-Dev-Id", "")
readInternet.InitClientCertificates()
readInternet.RetainBodyOnError(true)
response = ParseJson(readInternet.GetToString())
print "response:" response
Я также попытался использовать это для создания подписанных файлов cookie:
cookies = [
{Name:"CloudFront-Policy",Value:policy,Path:"/", Domain:"XXXXXXXXXX.cloudfront.net"},
{Name:"CloudFront-Expires",Value:"1561230905",Path:"/", Domain:"XXXXXXXXXX.cloudfront.net"},
{Name:"CloudFront-Signature",Value:fixedSignatureString,Path:"/", Domain:"XXXXXXXXXX.cloudfront.net"},
{Name:"CloudFront-Key-Pair-Id",Value:"APKAXXXXXXXXXXAVWQ", Path:"/", Domain:"XXXXXXXXXX.cloudfront.net"}
]
readInternet.EnableCookies()
readInternet.AddCookies(cookies)
Я также попробовал следующее вместо предыдущего метода добавления файлов cookie:
expires = "CloudFront-Expires=1561146117" //I have been careful to make sure the expire times are still good
sig = "CloudFront-Signature=" + fixedSignatureString
pairid = "CloudFront-Key-Pair-Id=APKAXXXXXXXXXXVWQ"
readInternet.AddHeader("Cookie",expires + "; " + sig + "; " + pairid)