9
votes

Meilleure façon de signer des données sur le formulaire Web avec certificat d'utilisateur

Nous avons une application Web C # où les utilisateurs se connecteront à l'aide d'un certificat numérique stocké dans leurs navigateurs.

des exemples que nous avons vus, vérifier leur identité sera facile une fois que nous activons SSL, car nous pouvons accéder aux champs du certificat, à l'aide de request.clientcertificate, pour vérifier le nom de l'utilisateur.

Nous avons également été demandés, cependant, de signer les données envoyées par l'utilisateur (quelques champs simples et un fichier binaire) afin que nous puissions prouver, sans aucun doute, quel utilisateur entrait chaque enregistrement dans notre base de données.

Notre première pensée créait une petite signature de texte comprenant les champs (et, si possible, le MD5 du fichier) et la chiffrer avec la clé privée du certificat, mais ...

Autant que je sache, nous ne pouvons pas accéder à la clé privée du certificat pour signer les données, et je ne sais pas s'il y a un moyen de signer les champs du navigateur, ou que nous n'avons aucune autre option que en utilisant une applet Java. Et si c'est ce dernier, comment nous le ferions (y a-t-il une applet open source que nous pouvons utiliser? Serait-il préférable de créer un nous-mêmes?)

Bien sûr, ce serait mieux s'il y avait un moyen de "signer" les champs reçus sur le serveur, en utilisant les données que nous pouvons accéder à partir du certificat de l'utilisateur. Mais sinon, aucune information sur la meilleure façon de résoudre le problème serait appréciée.


0 commentaires

4 Réponses :


1
votes

Nous ne pouvons pas accéder à la clé privée du certificat pour signer les données,

Si ce n'était pas vrai, le serveur peut alors se souvenir du certificat lui-même et l'utiliser pour apparaître pour être le vrai client lors de l'utilisation d'autres services.

I.e. invaliderait complètement l'utilisation de certificats clients pour authentifier le client.

Et je ne sais pas s'il y a un moyen de signer les champs du navigateur,

Que diriez-vous de poser cette question avec des balises côté client appropriées (par exemple JavaScript, navigateur) pour obtenir le bon public. (Je suis sûr que cela pourrait être fait avec l'extension du navigateur ou l'objet ActiveX - mais cela crée ses propres problèmes.)


5 commentaires

J'ai ajouté les balises pour voir si cela aide. P.s. Je connais les implications du serveur recevant la clé privée, mais il semble qu'il y ait des institutions publiques qui font cela (!!!!) et le client l'accepterait dans ce cas.


Dans votre commentaire ci-dessus, vous avez dit que le client devait pouvoir prouver à l'utilisateur que les données n'ont pas été modifiées. Être en possession de la clé privée empêcherait de prouver que vous n'avez pas modifié les données. Il est également très improbable que vous puissiez obtenir la clé privée de toute façon, c'est donc un point de sujet.


@salgiza Non, les institutions publiques sont pas Obtenir des clés privées client. C'est pourquoi cela s'appelle une "clé privée". L'authentification du client est identique à l'authentification du serveur - c'est-à-dire lorsque vous visitez un site Web sécurisé, votre navigateur ne reçoit certainement pas la clé privée du site lorsqu'elle vérifie la validité du certificat de serveur.


@pointy, je m'attendrais certainement à ce que ce soit le cas. Mais l'an dernier, un avertissement de sécurité provenant d'une applet Java installé dans certaines pages du gouvernement espagnol, m'a informé que ma clé privée devait être envoyée au serveur au serveur afin de signer les données que je soumettais (et remarquez-la. à quel point cela était peu sûr). Puzzled (et agacé) J'ai annulé, donc je ne peux pas dire avec certitude s'il s'agissait d'un avertissement mal écrit, mais cela ne l'a pas semblé.


@Andrew Ouais, tu as raison. Je suppose que je devais devenir un peu désespéré en raison du manque de réponses quand j'ai écrit ce commentaire.



2
votes

Vous devrez demander à votre service juridique s'il s'agit d'une "signature" assez forte mais avec chaque affichage des champs, le serveur enregistre les valeurs de champ et l'empreinte digitale du cert à partir de la poignée de main du certificat client. Oui, il s'agit de «pardable» que toute personne ayant une connaissance de l'empreinte digitale pourrait créer un faux enregistrement dans la base de données, mais avec une sécurité de base de données appropriée, vous pouvez supprimer ce vecteur d'attaque et avoir enregistré qui a affiché quoi (comme vous ne pouvez pas simuler l'empreinte digitale. du certificat client dans une authentification à deux voies de SSL)


1 commentaires

Malheureusement, nous devons signer à l'aide du certificat d'utilisateur. Ce n'est pas seulement une question d'entre nous (le client) étant capable de vérifier que les données n'ont pas été modifiées, mais une question de preuve à l'utilisateur qui a envoyé les données que nous ne l'avons pas modifiée (donc, afaik, la signature devrait être fait avant que les données arrivent sur le serveur).



1
votes

Il existe une méthode javascript crypto.signtext qui permet de signer du texte arbitraire avec le cerficate du client. Voici quelques docs et un exemple de formulaire signé . Il semble que seul Firefox soutient-le.

Pour IE Il y a un objet Capicom ActiveX (disponible en téléchargement à partir de MS). ici est un exemple de son utilisation.

Je ne suis pas sûr de la prise en charge de ces fonctionnalités dans différentes versions de navigateur et de système d'exploitation, vous devrez probablement le vérifier pour votre configuration.


3 commentaires

C'est bien de savoir que au moins un fournisseur de navigateur pensait que quelqu'un pourrait vouloir signer des formulaires avec leurs certificats! Il est dommage que cela ressemble à des développeurs Webkit ne pensaient que la même chose, cependant :( Capicom travaillerait certainement pour IE (nous l'avons effectivement utilisé il y a de nombreuses années), mais je pensais en quelque sorte quelque chose de mieux / plus standard serait apparu maintenant . Néanmoins, merci pour l'exemple! (Et espérons que Crypto.SignText est mis en œuvre dans d'autres navigateurs, car il a l'air assez utile)


Ouais. Je suis tombé sur quelques plaintes concernant cette fonctionnalité manquée par Chrome.


@Vlav j'ai vérifié sur la console de Safari et l'objet Crypto n'existe même pas. Je viens de vérifier s'il y a un bogue pour cela dans webkit, mais c'est le match le plus proche que j'ai trouvé: Bugs.WebKit.org/show_bug.cgi?id=24077 Oh, eh bien: S PS Je déteste le fait que Intro soumet maintenant des commentaires! (Je continue à soumettre des commentaires avant que je finisse de les écrire;))



8
votes

Je vous suggère d'utiliser Java-Applet. Cette approche est unifiée pour tous les navigateurs. Nous l'utilisons dans nos projets. Pour signer les données utilisateur, vous devez utiliser JCA API ( http: //download.oracle.com/javase/1.4.2/docs/guide/security/cryptostostospec.html#signature ). De plus, vous devrez résoudre un problème d'accès au magasin de certificats Windows à partir de Java.

Vous pouvez le résoudre de cette manière: P>

KeyStore keystore = KeyStore.getInstance("Windows-MY", "SunMSCAPI");

keystore.load(null, null);

HashMap<String,String> userPublicKeys = new HashMap<String,String>();

Enumeration<String> aliasesEnum = keystore.aliases();

if (!aliasesEnum.hasMoreElements())
    throw new Exception("No certificate!");

// list through windows personal store
while (aliasesEnum.hasMoreElements()) 
{
   String alias = aliasesEnum.nextElement();

   boolean isKey = keystore.isKeyEntry(alias);

   if (isKey)
   {
       BASE64Encoder encoder = new BASE64Encoder();
       encoder.encode(keystore.getCertificate(alias).getEncoded());

       userPublicKeys.put(alias, encoder.encode(keystore.getCertificate(alias).getEncoded()));
       System.out.println("Entry alias: " + alias); 
   }

   // sign
   PrivateKey privateKey = (PrivateKey) keystore.getKey(alias,null);           

   Provider provider = keystore.getProvider();
   // data to signed
   byte[] data ="test data".getBytes();
   // Signing the data
   Signature sig = Signature.getInstance("SHA1withRSA", provider);
   sig.initSign(privateKey);

   sig.update(data);
   byte[] signature = sig.sign();

   System.out.println(ByteArrayToFromHexDigits.bytesToHexString(signature).toUpperCase());
}


1 commentaires

Wow! Je ne l'ai pas testé, mais cela semble certainement bon. Jusqu'à ce que la crypto. * API est mise en œuvre par tous les vendeurs de navigateur, je suppose que vous devriez faire avec un applet Java devra faire.