Как реализовать расшифровку запросов и шифрование ответов в приложении Play?
Дано
trait CipherService {
def decryptData(data: Array[Byte])(implicit ec: ExecutionContext): Future[DecryptionError \/ Array[Byte]
def encryptEncrypt(data: Array[Byte)(implicit ec: ExecutionContext): Future[EncryptionError \/ Array[Byte]]
}
Как я могу реализовать расшифровку запроса и шифрование ответа, используя EssentialFilter
? Такое ощущение, что я застрял с Enumeratee
а также Iteratee
API.
2 ответа
trait CipherService {
def decryptData(data: Array[Byte])(implicit ec: ExecutionContext): Future[DecryptionError \/ Array[Byte]]
def encryptData(data: Array[Byte])(implicit ec: ExecutionContext): Future[EncryptionError \/ Array[Byte]]
}
trait BodyEncryptionFilter extends EssentialFilter with Results {
import play.api.libs.concurrent.Execution.Implicits._
val cipher: CipherService
def apply(next: EssentialAction): EssentialAction = new EssentialAction {
override def apply(requestHeader: RequestHeader): Iteratee[Array[Byte], Result] =
Iteratee.consume[Array[Byte]]().mapM { encryptedBody => // Collect body bytes
cipher.decryptData(encryptedBody) // Decrypt data
.toEitherT // Monad transformer
.flatMapF { decryptedBody =>
Enumerator(decryptedBody).run(next(requestHeader)) // Feed decrypted data to filter/action chain
.flatMap { result => // Here is the action result
result.body.run(Iteratee.consume[Array[Byte]]()) //Collect result body data
.flatMap { body =>
cipher.encryptData(body) // Ecnrypt body data
.toEitherT
.map { encryptedBody =>
result.copy(body = Enumerator(encryptedBody)) // Wrap it with Enumerator and copy result
}
.leftMap(_ => BadRequest("Encryption error")) // You will probably want proper error handling
.merge
}
}
.map(_.right)
}
.leftMap(_ => BadRequest("Encryption error"))
.merge
}
}
}
Итераторы и перечислители - это, в значительной степени, путь, когда вы ограничены байтными порциями. Шифрование - это операция очень низкого уровня, и ее очень трудно сделать правильно, поэтому инструменты также являются низкоуровневыми, маленькими и точными.
Поскольку шифрование и дешифрование данных очень сложно сделать правильно, большинство веб-платформ полагаются на HTTPS, а не внедряют его на прикладном уровне.
Если вы работаете с HTTP, то используйте nginx с OpenSSL, настроенным в соответствии с bettercrypto.org: https://www.playframework.com/documentation/2.3.x/ConfiguringHttps
Если вы используете внутреннюю защиту и хотите зашифровать данные по сети, вы должны использовать ipsec в транспортном режиме.