Как реализовать расшифровку запросов и шифрование ответов в приложении 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 в транспортном режиме.

Другие вопросы по тегам