Saltar al contenido principal

Seguridad

Al recibir una solicitud de notificación de un evento, es muy importante validar si la solicitud realmente provino de Kobana y no fue falsificada por un tercero.

Escenario de intrusión

Consideremos que la integración que está desarrollando sea de Kobana con un sistema de comercio electrónico. Al recibir el evento bank_billet.paid, que ocurre cuando se paga un boleto, el sistema de comercio electrónico libera el pedido para que se realice la entrega de la mercancía.

Imagine que un hacker descubre cuál es la URL del sistema de comercio electrónico que recibe las notificaciones y envía una notificación falsificada, como si fuera Kobana enviando. En ese caso, el evento del boleto siendo pagado no sucedió, pero su sistema liberará el pedido de todas formas.

Cómo protegerse

Para protegerse de este tipo de ataque, es necesario implementar una validación antes del procesamiento de todas las solicitudes, que certifique que la solicitud fue enviada por Kobana.

Todas las solicitudes realizadas por Kobana van con una firma en el encabezado X-Kobana-Signature. La firma es una cadena cifrada que se basa en el contenido de la solicitud y en la Clave Secreta del webhook.

Para validar si la solicitud es real, es necesario generar la firma y compararla con la firma que está en el encabezado de la solicitud. Si la firma recibida es igual a la firma generada, la solicitud es válida y segura.

Un hacker, sin tener acceso a la Clave Secreta, no puede generar la firma y por consiguiente no puede falsificar la solicitud.

Es muy relevante mantener la Clave Secreta segura, es decir, no poniéndola en el código fuente del sistema. Se recomienda almacenarla como variable de entorno en el servidor de producción o sistema de configuración que sea seguro y cifrado.

Cualquier persona con acceso a la Clave Secreta es capaz de falsificar solicitudes como si vinieran de Kobana. Si cree que la Clave Secreta se ha filtrado de alguna forma, se recomienda renovar la clave en la página de visualización de los datos del webhook.

Clave Secreta del webhook

Para obtener la Clave Secreta del Webhook, vaya a la página de Webhooks en el menú Integraciones -> Webhooks -> Cuentas y seleccione el Webhook en cuestión.

Haga clic en copiar en el botón azul.

Ejemplos de códigos

# El ejemplo a continuación está usando el framework minimalista en Ruby,
# llamado [Sinatra](http://www.sinatrarb.com/).

require 'sinatra'
require 'json'

post '/callbacks/kobana' do
verify_signature

payload = JSON.parse(request_body)
"Event Code: #{payload['event_code']}"
end

def request_body
@request_body ||= request.body.read.to_s
end

def secret_key
ENV['WEBHOOK_SECRET_KEY']
end

def signature_from_request
request.env['HTTP_X_KOBANA_SIGNATURE'].split('=').last
end

def generated_signature
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret_key, request_body)
end

def verify_signature
return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature_from_request, generated_signature)
end

Algunas observaciones son importantes:

  • La firma se genera siguiendo el estándar HMAC con SHA256;
  • La firma enviada en X_KOBANA_SIGNATURE siempre comienza con sha256= y debe usarse el valor después del = en la comparación entre nuestra clave y la clave que será generada por usted;
  • La firma debe generarse usando la Clave Secreta del Webhook, que es individual y única por Webhook y por ambiente(Sandbox o Production), y el contenido(body) de la solicitud POST enviado en RAW(sin ningún pretratamiento por parte de su servidor o lib) (request.body);
  • La Clave Secreta no debe colocarse hard-coded en el código fuente y se recomienda que se almacene en una variable de entorno;
  • No se recomienda usar el operador == para comparar la firma recibida y la firma generada. Un método como Rack::Utils.secure_compare ejecuta una comparación segura contra algunos tipos de timing attacks. Investigue cómo hacer una comparación segura en el lenguaje que esté utilizando.