API de seguridad para desarrolladores de Building Blocks
Blackboard se ha integrado con una biblioteca de seguridad de código abierto de mejores prácticas de la API de seguridad empresarial (ESAPI) del Proyecto de Aplicaciones Web Abiertas (OWASP). Esta biblioteca de seguridad se envía de forma predeterminada instalada en Blackboard a través de un Bloque de construcción llamado "Módulo de seguridad ESAPI" y es necesaria para el funcionamiento del sistema. Blackboard recomienda encarecidamente a todos los desarrolladores de Building Block que aprovechen esta nueva API de seguridad basada en OWASP ESAPI para Java y ESAPI para JavaScript. Estos cambios en la API de seguridad no solo incluyen implementaciones de mejores prácticas, sino que también aumentan la facilidad de uso de los métodos a través de una nomenclatura coherente.
Nota
En versiones posteriores, la API de bloques de creación del módulo de seguridad ESAPI es parte del código principal de Blackboard y está disponible de forma predeterminada.
Como parte de las prácticas de codificación segura, la entrada que puede ser influenciada por los usuarios, ya sean confiables o no, debe validarse en el lado del servidor antes del procesamiento (validación de entrada), así como antes de la visualización (validación de salida o escape). Esto ayuda a garantizar la resistencia del sistema y evita problemas de seguridad como secuencias de comandos entre sitios.
Validación de entrada
Al recibir la entrada de la solicitud, valide siempre y valide siempre el lado del servidor. Blackboard ha implementado varios casos de uso populares que requieren validación. A continuación se proporcionan algunos ejemplos.
blackboard.platform.security.ValidationUtility.isValidDirectoryPath( String )
blackboard.platform.security.ValidationUtility.isValidGuid( String )
blackboard.platform.security.ValidationUtility.isValidEnumeratedType( Enumeración, cadena )
Validación/codificación/escape de salida
Al mostrar cualquier entrada, asegúrese siempre de que se muestre en el contexto correcto en el que se incrustará:
Métodos Java
blackboard.platform.security.EscapeUtility.escapeForHTML ( String )
blackboard.platform.security.EscapeUtility.escapeForHTMLAttribute ( String )
blackboard.platform.security.EscapeUtility.escapeForJavascript ( Cadena )
blackboard.platform.security.EscapeUtility.escapeForUrl ( Cadena )
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 de JavaScript
Todos los métodos de ESAPI para JavaScript están disponibles para su uso. Una lista de métodos más utilizados:
$ESAPI.encoder().canonicalize( String )
$ESAPI.encoder().encodeForHTML( String )
$ESAPI.encoder().encodeForHTMLAttribute( String )
$ESAPI.encoder().encodeForCSS( String )
$ESAPI.encoder().encodeForJavaScript( String )
$ESAPI.encoder().encodeForURL( String )
Descifrar texto cifrado
Descifrar el contexto cifrado
Para cifrar los datos durante el paso de contexto, Blackboard y la URL externa deben tener acceso a la misma clave de cifrado de contexto. La clave debe crearse desde la función Administrar clave de cifrado de contexto disponible en el Panel del administrador. Una vez que se ha creado la clave, debe descargarse y distribuirse a servidores externos que aceptarán el contexto.
Ejemplo de código
Después de la descarga de una clave de cifrado de contexto, debe estar disponible para la URL que recibirá datos cifrados a través del paso de contexto. En el ejemplo de código siguiente se muestra cómo descifrar mediante programación los datos de contexto cifrados en la dirección URL externa cuando se pasa.
El objeto indicado por la URL de destino (en este caso, index.jsp) podría descifrar el contexto de la siguiente manera (importando blackboard.client.decryption.*):
String context = request.getParameter("context");//si isEncryptionEnabled = false, se utilizará la codificación base 64 en lugar de habilitarboolean isEncryptionEnabled = true; ContextDecryptor bfd = ContextDecryptorFactory.getContextDecryptor(isEncryptionEnabled ); recuperar la clave de cifrado de Blackboard como una clave de archivo o InputStream File = new File( strKeyLocation ); or InputStream key = // detalle de implementación...// para descifrar simplemente la cadena de contexto String decryptedContext = bfd.decrypt( context, key );// o, para obtener un HashMap de todos los pares clave-valorHashMap map = bfd.parseEncryptedContext( context, key );// luego busque en el HashMap un valor esperado, y continue.if (map.containsKey( "user" ){ // ejecutar...}
Resolución de varias claves
El ejemplo de código anterior es útil cuando existe una relación uno a uno entre la URL externa y Blackboard. Para los casos en los que una URL externa admite un bloque de construcción para varias instancias de Blackboard, el nombre de host de la instancia se puede usar para manejar varias claves.
En el siguiente ejemplo, la clave se encuentra a través de la asociación con el nombre de host de la instancia o instalación virtual de Blackboard. En este caso, el nombre de host es physics.yourinstitución.com. Dado que el código de descifrado del cliente tiene la capacidad de pasar una clave de descifrado al objeto ContextDecryptor, el servidor cliente debe poder asignar un nombre de host a su clave adecuada (normalmente se accede como un archivo, pero puede ser una secuencia).
Los desarrolladores de servidores de Bloque de Construcción pueden escribir un contenedor simple que:
Extrae el nombre de host de la solicitud.
Busca el archivo de clave de cifrado en el mapa hostname-encryptionKey.
Pasa la clave de cifrado al método
decrypt().
Contenedor de pseudocódigo implementado por un objeto de utilidad cliente-servidor:
/**
* Pseudocódigo de utilidad
*/
decryptByHostname( solicitud HttpServletRequest )
{
obtener el parámetro de contexto de la solicitud
Contexto de cadena = request.getParameter("contexto");
Determinar si el contexto está cifrado
String strEncryptInd = request.getParameter("cifrar");
if ( (strEncryptInd != null) && (strEncryptInd.equalsIgnoreCase("y")) )
{
isEncrypted = verdadero;
}
si isEncrypted, busque la clave
clave = nulo;
if (isEncriptado)
{
obtener el nombre de host de HttpUtils.getRequestURL().getHost();
obtener el mapa de claves, posiblemente almacenado como un archivo de propiedades en el formato
// physics.yourinstitution.com= /key/file/location/physics_yourinstitution_com/key.sec
obtener la clave de cifrado del mapa como un archivo o una secuencia de entrada,
Dependiendo de los detalles de implementación del cliente (la clave se pasa como null si
isEncrypted= false, y en su lugar se usa Base64Encoding)
}
Descifrador de ContextDecryptor =
ContextDecryptorFactory.getContextDecryptor(isEncrypted);
A continuación, devuelve los valores pasados en el contexto como
un HashMap de pares clave-valor
Valores de HashMap = decryptor.parseEncryptedContext(contexto, clave);
o una cadena
Valores de cadena = decryptor.decrypt(contexto, clave);
valores devueltos;
}