API de segurança para desenvolvedores de Building Blocks
A Blackboard se integrou a uma biblioteca de segurança de fonte aberta de práticas recomendadas da API de segurança empresarial (ESAPI) do Open Web Application Project (OWASP). Essa biblioteca de segurança é fornecida por padrão instalada no Blackboard por meio de um Building block chamado "Módulo de segurança ESAPI" e é necessária para a operação do sistema. A Blackboard recomenda enfaticamente que todos os desenvolvedores do Building block aproveitem essa nova API de segurança baseada em OWASP ESAPI para Java e ESAPI para JavaScript. Essas alterações da API de segurança não incluem apenas implementações de práticas recomendadas, mas também aumentam a facilidade de uso dos métodos por meio de nomenclatura consistente.
Nota
Em versões posteriores, a API de Building block do módulo de segurança ESAPI faz parte do código principal da Blackboard e está disponível por padrão.
Como parte das práticas de codificação segura, a entrada que pode ser influenciada pelos usuários, confiáveis ou não, deve ser validada no lado do servidor antes do processamento (validação de entrada), bem como antes da exibição (validação ou escape de saída). Isso ajuda a garantir a resiliência do sistema e evita problemas de segurança, como scripts entre sites.
Validação de entrada
Ao receber entrada da solicitação, sempre valide e sempre valide no lado do servidor. A Blackboard implementou vários casos de uso populares que exigem validação. Alguns exemplos são fornecidos abaixo.
blackboard.platform.security.ValidationUtility.isValidDirectoryPath( String )
blackboard.platform.security.ValidationUtility.isValidGuid( String )
blackboard.platform.security.ValidationUtility.isValidEnumeratedType( Enum, String )
Validação/codificação/escape de saída
Ao exibir qualquer entrada, sempre certifique-se de que ela seja exibida no contexto correto em que será incorporada:
Métodos Java
blackboard.platform.security.EscapeUtility.escapeForHTML ( String )
blackboard.platform.security.EscapeUtility.escapeForHTMLAttribute ( String )
blackboard.platform.security.EscapeUtility.escapeForJavascript ( String )
blackboard.platform.security.EscapeUtility.escapeForUrl ( String )
blackboard.platform.security.EscapeUtility.escapeForCSS ( String )
blackboard.platform.security.EscapeUtility.escapeForXML ( String )
blackboard.platform.security.EscapeUtility.escapeForXMLAttribute ( String )
Métodos JSP
${bbNG:EscapeForHTML( String )}
${bbNG:EscapeForJavascript( String )}
${bbNG:EscapeForURL( String )}
${bbNG:EscapeForCSS( String )}
${bbNG:EscapeForXML( String )}
${bbNG:EscapeForXMLAttribute( String )}
Métodos JavaScript
Todos os métodos ESAPI para JavaScript estão disponíveis para uso. Uma lista dos métodos mais comumente usados:
$ESAPI.encoder().canonicalize( String )
$ESAPI.encoder().encodeForHTML( String )
$ESAPI.encoder().encodeForHTMLAttribute( String )
$ESAPI.encoder().encodeForCSS( String )
$ESAPI.encoder().encodeForJavaScript( String )
$ESAPI.encoder().encodeForURL( String )
Decifrar texto criptografado
Decifrar contexto criptografado
Para criptografar dados durante a passagem de contexto, o Blackboard e o URL externo devem ter acesso à mesma chave de criptografia por contexto. A chave deve ser criada a partir do recurso Gerenciar chave de criptografia por contexto disponível no Painel do administrador. Depois que a chave for criada, ela deverá ser baixada e distribuída para servidores externos que aceitarão o contexto.
Exemplo de código
Depois de baixar uma chave de criptografia por contexto, ela deve ser disponibilizada para a URL que receberá dados criptografados por meio de passagem de contexto. O exemplo de código abaixo mostra como decifrar programaticamente dados de contexto criptografados na URL externa quando ela é passada.
O objeto indicado pelo URL de destino (neste caso, index.jsp) pode descriptografar o contexto da seguinte maneira (importando blackboard.client.decryption.*):
String context = request.getParameter("context");//se isEncryptionEnabled = false, a codificação de base 64 será usada //de encryptionboolean isEncryptionEnabled = true; ContextDecryptor bfd = ContextDecryptorFactory.getContextDecryptor(isEncryptionEnabled ); recuperar a chave de criptografia do Blackboard como uma chave de arquivo ou arquivo InputStream = new File( strKeyLocation ); ou InputStream key = // detalhe da implementação...// para simplesmente descriptografar a string de contexto String decryptedContext = bfd.decrypt( context, key );// ou, para obter um HashMap de todos os pares de valores-chaveHashMap map = bfd.parseEncryptedContext( context, key );// em seguida, procure no HashMap por um valor esperado e continue.if (map.containsKey( "user" ){ // execute...}
Resolvendo várias chaves
O exemplo de código acima é útil quando há uma relação um-para-um entre o URL externo e o Blackboard. Para instâncias em que um URL externo é compatível com um Building block para várias instâncias do Blackboard, o nome do host da instância pode ser usado para lidar com várias chaves.
No exemplo abaixo, a chave é encontrada por meio da associação com o nome do host para a instância ou instalação virtual do Blackboard. Nesse caso, o nome do host é physics.yourinstituição.com. Como o código de descriptografia do cliente tem a capacidade de passar uma chave de descriptografia para o objeto ContextDecryptor, o servidor cliente deve ser capaz de mapear um nome de host para sua chave apropriada (geralmente acessada como um arquivo, mas pode ser um fluxo de entrada).
Os desenvolvedores de servidores do Building Block podem escrever um wrapper simples que:
Extrai o nome do host da solicitação.
Procura o arquivo de chave de criptografia no mapa hostname-encryptionKey.
Passa a chave de criptografia para o método
decrypt().
Wrapper de pseudocódigo implementado por um objeto utilitário cliente-servidor:
/**
* Pseudocódigo do utilitário
*/
decryptByHostname( Solicitação HttpServlet)
{
Obter parâmetro de contexto da solicitação
String contexto = request.getParameter("contexto");
Determinar se o contexto está criptografado
String strEncryptInd = request.getParameter("criptografar");
if ( (strEncryptInd != null) && (strEncryptInd.equalsIgnoreCase("y")) )
{
isEncrypted = true;
}
if isEncrypted, procure a chave
chave = nulo;
if (isEncrypted)
{
obtenha o nome do host de HttpUtils.getRequestURL().getHost();
obter mapa de chaves, possivelmente armazenado como um arquivo de propriedade no formato
// physics.yourinstitution.com= /key/file/location/physics_yourinstitution_com/key.sec
obter a chave de criptografia do mapa como um arquivo ou um fluxo de entrada,
dependendo dos detalhes de implementação do cliente (a chave é passada como nula se
isEncrypted= false, e Base64Encoding é usado em seu lugar)
}
Descriptografador de contexto =
ContextDecryptorFactory.getContextDecryptor(isEncrypted);
em seguida, retornam os valores passados no contexto como
um HashMap de pares de valores-chave
Valores de HashMap = decryptor.parseEncryptedContext(contexto, chave);
ou uma string
Valores de string = decryptor.decrypt(contexto, chave);
valores retornados;
}