2010-05-10 12 views
18

¿Hay alguna forma de asegurar su ensamblaje al clase/propiedad & clase/método para evitar el uso/llamada de ellos de otro ensamblaje que no esté firmado por nuestra empresa?Asegure los ensamblajes C# de personas que llaman no autorizadas

Me gustaría hacer esto sin ningún requisito sobre nombres fuertes (como usar StrongNameIdentityPermission) y seguir con la forma en que se firma un ensamblaje. Realmente no quiero recurrir al uso del atributo InternalsVisibleTo ya que no se puede mantener en un ecosistema de software en constante cambio.

Por ejemplo:

Escenario uno

Foo.dll está firmada por mi empresa y bar.dll no está firmado en absoluto.

Foo tiene Clase A bar tiene clase B

Clase A tiene método público GetSomething() Clase B intenta llamar Foo.A.GetSomething() y se rechazó

rechacen ser una excepción o siendo ignorada de alguna manera

Escenario dos

Foo.dll está firmada por mi empresa y Moo.dll también está firmada por mi empresa.

Foo tiene Clase A MOO ha Clase C

Clase A ha rechazado no se GetSomething método público() Clase C intenta llamar Foo.A.GetSomething() y

+0

Explique "firmado". Llamó específicamente a los nombres no fuertes, por lo que no está hablando de la opción de firma disponible en .NET (porque eso es una denominación fuerte). ¿En su lugar está indicando la firma de authenticode? –

+0

Firmado pero no fuerte, Strong Naming es la firma y más. Entonces, si tiene un certificado de Verisign, puede usarlo para firmar un archivo DLL, EXE o lo que sea. –

+0

Correcto, ¿entonces autenticar firmando luego a través de un certificado de firma de código? –

Respuesta

6

Si quiere limitar las llamadas a solo el código que ha sido autenticado por un certificado específico, puede usar CAS (simplemente no StrongNameIdentityPermission).

Use PublisherIdentityPermission como si hubiera usado algún permiso de CAS. O si quiere hacerlo declarativamente, use an attribute.

+0

gracias, voy a profundizar en esto. Parece que podría resolver el problema a primera vista. –

+0

¿Puede publicar el ejemplo de código? (Http://pastebin.com/ o cualquier alojamiento de código puede ayudar) – Elshan

+0

Por MSDN, esta solución ya no es válida a partir de .NET 4.0. Los permisos basados ​​en identidad ya no son aplicados por el marco. –

2

he visto DLL escrito por compañías (más notablemente Pegasus Imaging) que usa un sistema de desafío/respuesta para desbloquear el ensamblaje. El comprador de la DLL se proporciona con un "Código de licencia", vinculado al nombre del comprador, que el consumidor de la DLL utiliza para desbloquear un subconjunto específico de las características de la DLL.

Por lo tanto, cuando el ensamblaje se utiliza por primera vez por la aplicación, se llama al método Unlock() en el ensamblaje. El nombre de usuario y el código de desbloqueo se pasan y se ejecutan a través de un algoritmo que verifica la identidad, presumiblemente usando un algoritmo de encriptación de clave pública de algún tipo.

Hay algunos bits codificados en el código de desbloqueo que especifican características; estos bits luego establecen algunos indicadores de características en el ensamblaje. Todas las funciones de llamada deben verificar estos indicadores para determinar si la característica apropiada está habilitada. El método Unlock() se llama solo una vez y es válido durante el tiempo de vida del ensamblaje cargado.

Por supuesto, ya que tiene que proporcionar la "clave privada" en el ensamblado, este procedimiento no es a prueba de intrusiones (¿qué es?), Pero es razonablemente seguro, y mantendrá a la gente honesta honesta.

+0

Por supuesto, puedo escribir mi propio pequeño framework que CADA método en un ensamblado que necesito asegurar llamaría a un método bool: Verify() o algo así antes de permitir que proceda a hacer lo que se supone que debe hacer. Sin embargo, estoy buscando algo que espero sea parte de .Net Framework y se puede agregar a AssemblyInfo, básicamente algo más global que se ocupe del trabajo seguro en tiempo de compilación. –

+0

Excelente. Estuve buscando un summat así por un tiempo. ¿Por qué no está más de este tipo de detalles de seguridad en la web? –

+0

@Creepy Gnome: no necesita escribir su propio marco para eso, para eso está el AOP. – R0MANARMY

0

No creo que haya una manera de hacerlo si no controla el entorno de ejecución bajo el cual se ejecuta el código. El código que se ejecuta con plena confianza en la máquina de un usuario podría evitar cualquier restricción que haya agregado. Por ejemplo, el código de confianza total podría invocar métodos privados o internos con las API de reflexión, por lo que incluso el uso de InternalsVisibleToAttribute no funcionaría.

Si controla el entorno de ejecución, puede crear un dominio de aplicación donde su código sea completamente confiable y el código de tercero sea parcialmente confiable y no pueda llamar a su código a menos que coloque un AllowPartiallyTrustedCallersAttribute (APTCA) en el ensamblaje. Puede restringir qué métodos se pueden invocar en un ensamblaje APTCA con los atributos SecurityCritical y SecuritySafeCritical.

How to: Run Partially Trusted Code in a Sandbox

2

En primer lugar, como se dé cuenta, no es suficiente para utilizar InternalsVisibleTo - también se tendría que firmar y fuertemente nombre de cada conjunto para asegurar que alguien no sólo puede suplantar el nombre.

Ahora que eso está fuera del camino, tendría que desarrollar una implementación de desafío y respuesta por su cuenta; esto no es algo que pueda hacer a menos que esté dispuesto a usar el enfoque InternalsVisibleTo que explícitamente describe que no usa. no quiero usar

En un modelo C-R, necesitaría pasar algún tipo de token con cada llamada al método (o tal vez solo para crear una instancia de un objeto). El token sería una clase que solo su código puede crear una instancia de - Haría de esta una clase interna del ensamblado que desea consumir y la haré accesible con InternalsVisibleTo - de esta manera solo una clase necesita ser administrada:

// SharedAssembly.dll 
// marks ConsumingAssembly.dll as having access to internals... 

internal sealed class AccessToken { } 

public class SecuredClass 
{ 
    public static bool WorkMethod(AccessToken token, string otherParameter) 
    { 
     if(token == null) 
      throw new ArgumentException(); // you may want a custom exception. 

     // do your business logic... 
     return true;   
    } 
} 



// ConsumingAssembly.dll (has access via InternalsVisibleTo) 

public class MainClass 
{ 
    public static void Main() 
    { 
     var token = new AccessToken(); // can create this because of IVT access 
     SecuredClass.WorkMethod(token, ""); // tada... 
    } 
} 

Puede poner la clase AccessToken en un tercer ensamblaje que conozcan tanto el proveedor de servicios como el consumidor, para que no tenga que mantener constantemente un grupo diferente para acceder a las clases de tokens para diferentes ensamblajes.

Crear un mecanismo C-R para cada método es engorroso y tedioso. Tampoco es 100% infalible: alguien con suficiente tiempo y paciencia probablemente pueda encontrar una forma de evitarlo.

La mejor opción (que puede o no ser posible en su caso) sería mantener su código privado en sus propios servidores y solo exponerlo como un servicio web (o algo similar). Esto le permite administrar activamente la accesibilidad a su IP y le permite actualizar quién tiene acceso de manera centralizada (en lugar de distribuida). Las tecnologías ya existen para restringir el acceso a los servicios web mediante el uso de certificados, firmas de mensajes y encriptación. Esta sería la forma más confiable (y comprobada) de controlar el acceso a su IP.

2

¡Creo que es demasiado alboroto para nada! Si realmente quiere seguridad, coloque su código detrás de un servidor y use una arquitectura cliente-servidor. O servicios web. O algo intermedio como WCF, o remoto. Luego use autenticación para autenticar a un cliente.

Heck puedes hacer que todo sea privado, exponer una API pública y rootear las llamadas localmente.

Proteger un dll de personas que llaman sin autorización en un entorno de escritorio solamente hace que el asunto sea más complicado y más difícil de trabajar. Sin mencionar que se vería bastante feo por dentro.

Veo que surgen algunas convenciones. Y eso puede funcionar para ti. Pero no le brinda la "seguridad total" que necesita.Si tiene un ensamblaje que se supone que está oculto a los clientes, no lo coloque en el GAC. Use espacios de nombres postfijo con algo como "INTERNO".

6

Obviamente, debe realizar un control en cada llamada desde el método llamado: cualquier sistema externo que intente imponer las restricciones se puede eludir fácilmente mediante la reflexión.

Desde dentro del método que puede utilizar

new StackTrace().GetFrame(1).GetMethod().Module.Assembly 

para obtener el conjunto de llamadas. Ahora puede usar

callingAssembly.GetName().GetPublicKey() 

para obtener la clave pública del conjunto que realiza la llamada y compararla con la clave pública del conjunto llamado. Si coinciden, suponiendo que todos sus ensamblajes estén firmados con el mismo par de claves, la persona que llama se acepta como una persona legitimada.

Pero hay un orificio de bucle: un ensamblado de un tercero se puede retrasar con la clave pública de su empresa y excluirse de la verificación de la firma digital. En consecuencia, el cargador cargará el ensamblado de terceros con un nombre seguro y la clave pública de su empresa, incluso si aún no está firmado. Para cerrar este agujero de bucle, debe verificar la firma. No hay una API administrada y hay que P/Invoke

Boolean StrongNameSignatureVerificationEx(
    String wszFilePath, 
    Boolean fForceVerification, 
    ref Boolean pfWasVerified) 

con fForceVerification conjunto de true y comprobar si el resultado es true.

En conjunto, esto puede ser bastante sobrecarga por llamada. La tentación es probablemente almacenar en caché el resultado, pero suponiendo que una persona que llama con permiso de reflexión probablemente no sea muy difícil manipular dicho caché. Por otro lado, nunca estarás 100% seguro. Quien controle el sistema es libre de hacer (casi) todo lo que quiera: adjuntar un depurador, modificar el contenido de la memoria, manipular bibliotecas o todo el tiempo de ejecución. Finalmente, también debe proteger eficazmente su ensamblaje contra la descompilación y la modificación.

+0

Con respecto a esta comprobación: nuevo StackTrace(). GetFrame (1) .GetMethod(). Module.Assembly, ¿No deberíamos verificar los ensamblajes en la pila? De lo contrario, podría haber un ensamblaje intermediario (o aplicación de llamada) que pertenece al atacante. –

+0

Si realiza la verificación en cada método (y propiedad), siempre encontrará a un llamante no autorizado cuando intente por primera vez llamar al código protegido; no es necesario caminar por la pila. –

Cuestiones relacionadas