Existe-t-il une API publique permettant d’utiliser le Google Authenticator (authentification à deux facteurs) sur des applications Web à exécution automatique (par exemple, une pile LAMP)?
Le projet est open source. Je ne l'ai pas utilisé. Mais il utilise un algorithme documenté (indiqué dans la RFC répertoriée sur la page de projet open source) et les implémentations de l'authentificateur prennent en charge plusieurs comptes.
Le processus actuel est simple. Le code temporel unique est essentiellement un générateur de nombre pseudo aléatoire. Un générateur de nombre aléatoire est une formule qui, une fois donnée, commence à créer un flux de nombres aléatoires. Étant donné une graine, alors que les nombres peuvent être aléatoires les uns par rapport aux autres, la séquence elle-même est déterministe. Ainsi, une fois que votre appareil et le serveur sont "synchronisés", les numéros aléatoires créés par l'appareil, chaque fois que vous appuierez sur le "bouton du numéro suivant", seront identiques, au hasard, au nombre que le serveur attend.
Un système de mot de passe à usage unique sécurisé est plus sophistiqué qu'un générateur de nombres aléatoires, mais le concept est similaire. Il existe également d'autres détails permettant de garder le périphérique et le serveur synchronisés.
Donc, il n'est pas nécessaire que quelqu'un d'autre héberge l'authentification, comme, par exemple, dit OAuth. Au lieu de cela, vous devez implémenter cet algorithme compatible avec les applications fournies par Google pour les appareils mobiles. Ce logiciel est (devrait être) disponible sur le projet open source.
Selon votre niveau de sophistication, vous devriez avoir tout ce dont vous avez besoin pour implémenter le côté serveur de ce processus, à savoir le projet OSS et le RFC. Je ne sais pas s'il existe une implémentation spécifique pour votre logiciel serveur (PHP, Java, .NET, etc.)
Mais, spécifiquement, vous n'avez pas besoin d'un service externe pour gérer cela.
L'algorithme est documenté dans RFC6238 . Va un peu comme ça:
J'ai eu un jeu implémentant l'algorithme en javascript ici: http://blog.tinisles.com/2011/10/google-authenticator-one-time-password-algorithm-in-javascript/
Il y a une variété de bibliothèques pour PHP (The LAMP Stack)
PHP
https://code.google.com/p/ga4php/
http://www.idontplaydarts.com/2011/07/google-totp-two-factor-authentication-for-php/
Vous devez faire attention lorsque vous implémentez une authentification à deux facteurs, vous devez vous assurer que vos horloges sur le serveur et le client sont synchronisées, qu'il existe une protection contre les attaques brutales sur le jeton et que la valeur initiale utilisée est suffisamment grande.
Vous pouvez utiliser ma solution, posté comme réponse à ma question (il y a le code Python complet et explication):
Je pense que c'est assez facile à implémenter dans PHP ou dans Perl. Si vous avez des problèmes avec cela, s'il vous plaît faites le moi savoir.
J'ai aussi posté mon code sur GitHub en tant que module Python.
J'ai trouvé ceci: https://github.com/PHPGangsta/GoogleAuthenticator . Je l'ai testé et fonctionne bien pour moi.
Theres: https://www.gauthify.com qui l'offre en tant que service
Pas LAMP mais si vous utilisez C # c'est le code que j'utilise:
Code originaire de:
https://github.com/kspearrin/Otp.NET
La classe Base32Encoding provient de cette réponse:
https://stackoverflow.com/a/7135008/3850405
Exemple de programme:
class Program
{
static void Main(string[] args)
{
var bytes = Base32Encoding.ToBytes("JBSWY3DPEHPK3PXP");
var totp = new Totp(bytes);
var result = totp.ComputeTotp();
var remainingTime = totp.RemainingSeconds();
}
}
Totp:
public class Totp
{
const long unixEpochTicks = 621355968000000000L;
const long ticksToSeconds = 10000000L;
private const int step = 30;
private const int totpSize = 6;
private byte[] key;
public Totp(byte[] secretKey)
{
key = secretKey;
}
public string ComputeTotp()
{
var window = CalculateTimeStepFromTimestamp(DateTime.UtcNow);
var data = GetBigEndianBytes(window);
var hmac = new HMACSHA1();
hmac.Key = key;
var hmacComputedHash = hmac.ComputeHash(data);
int offset = hmacComputedHash[hmacComputedHash.Length - 1] & 0x0F;
var otp = (hmacComputedHash[offset] & 0x7f) << 24
| (hmacComputedHash[offset + 1] & 0xff) << 16
| (hmacComputedHash[offset + 2] & 0xff) << 8
| (hmacComputedHash[offset + 3] & 0xff) % 1000000;
var result = Digits(otp, totpSize);
return result;
}
public int RemainingSeconds()
{
return step - (int)(((DateTime.UtcNow.Ticks - unixEpochTicks) / ticksToSeconds) % step);
}
private byte[] GetBigEndianBytes(long input)
{
// Since .net uses little endian numbers, we need to reverse the byte order to get big endian.
var data = BitConverter.GetBytes(input);
Array.Reverse(data);
return data;
}
private long CalculateTimeStepFromTimestamp(DateTime timestamp)
{
var unixTimestamp = (timestamp.Ticks - unixEpochTicks) / ticksToSeconds;
var window = unixTimestamp / (long)step;
return window;
}
private string Digits(long input, int digitCount)
{
var truncatedValue = ((int)input % (int)Math.Pow(10, digitCount));
return truncatedValue.ToString().PadLeft(digitCount, '0');
}
}
Base32Encoding:
public static class Base32Encoding
{
public static byte[] ToBytes(string input)
{
if (string.IsNullOrEmpty(input))
{
throw new ArgumentNullException("input");
}
input = input.TrimEnd('='); //remove padding characters
int byteCount = input.Length * 5 / 8; //this must be TRUNCATED
byte[] returnArray = new byte[byteCount];
byte curByte = 0, bitsRemaining = 8;
int mask = 0, arrayIndex = 0;
foreach (char c in input)
{
int cValue = CharToValue(c);
if (bitsRemaining > 5)
{
mask = cValue << (bitsRemaining - 5);
curByte = (byte)(curByte | mask);
bitsRemaining -= 5;
}
else
{
mask = cValue >> (5 - bitsRemaining);
curByte = (byte)(curByte | mask);
returnArray[arrayIndex++] = curByte;
curByte = (byte)(cValue << (3 + bitsRemaining));
bitsRemaining += 3;
}
}
//if we didn't end with a full byte
if (arrayIndex != byteCount)
{
returnArray[arrayIndex] = curByte;
}
return returnArray;
}
public static string ToString(byte[] input)
{
if (input == null || input.Length == 0)
{
throw new ArgumentNullException("input");
}
int charCount = (int)Math.Ceiling(input.Length / 5d) * 8;
char[] returnArray = new char[charCount];
byte nextChar = 0, bitsRemaining = 5;
int arrayIndex = 0;
foreach (byte b in input)
{
nextChar = (byte)(nextChar | (b >> (8 - bitsRemaining)));
returnArray[arrayIndex++] = ValueToChar(nextChar);
if (bitsRemaining < 4)
{
nextChar = (byte)((b >> (3 - bitsRemaining)) & 31);
returnArray[arrayIndex++] = ValueToChar(nextChar);
bitsRemaining += 5;
}
bitsRemaining -= 3;
nextChar = (byte)((b << bitsRemaining) & 31);
}
//if we didn't end with a full char
if (arrayIndex != charCount)
{
returnArray[arrayIndex++] = ValueToChar(nextChar);
while (arrayIndex != charCount) returnArray[arrayIndex++] = '='; //padding
}
return new string(returnArray);
}
private static int CharToValue(char c)
{
int value = (int)c;
//65-90 == uppercase letters
if (value < 91 && value > 64)
{
return value - 65;
}
//50-55 == numbers 2-7
if (value < 56 && value > 49)
{
return value - 24;
}
//97-122 == lowercase letters
if (value < 123 && value > 96)
{
return value - 97;
}
throw new ArgumentException("Character is not a Base32 character.", "c");
}
private static char ValueToChar(byte b)
{
if (b < 26)
{
return (char)(b + 65);
}
if (b < 32)
{
return (char)(b + 24);
}
throw new ArgumentException("Byte is not a value Base32 value.", "b");
}
}
Oui, aucun service réseau n'est nécessaire, car Google Authenticator app ne communiquera pas avec le serveur Google. Elle restera synchronisée avec le secret initial généré par votre serveur (entrée dans votre téléphone à partir du code QR) pendant que le temps passe.
Pour ceux qui utilisent Laravel, ceci https://github.com/sitepoint-editors/google-laravel-2FA est un moyen agréable de résoudre ce problème.
Pour les utilisateurs C #, exécutez cette application console simple pour comprendre comment vérifier le code de jeton ponctuel. Notez que nous devons d’abord installer la bibliothèque Otp.Net à partir du paquet Nuget.
static string secretKey = "JBSWY3DPEHPK3PXP"; //add this key to your Google Authenticator app
private static void Main(string[] args)
{
var bytes = Base32Encoding.ToBytes(secretKey);
var totp = new Totp(bytes);
while (true)
{
Console.Write("Enter your code from Google Authenticator app: ");
string userCode = Console.ReadLine();
//Generate one time token code
string tokenInApp = totp.ComputeTotp();
int remainingSeconds = totp.RemainingSeconds();
if (userCode.Equals(tokenInApp)
&& remainingSeconds > 0)
{
Console.WriteLine("Success!");
}
else
{
Console.WriteLine("Failed. Try again!");
}
}
}