Google Authenticator dostępny jako usługa publiczna?

Czy istnieje publiczne API do korzystania z Google Authenticator (uwierzytelnianie dwuskładnikowe) w aplikacjach internetowych działających samodzielnie (np. LAMP stack)?

Author: mate64, 2011-02-23

9 answers

Projekt jest open source. Nie użyłem go. Ale używa udokumentowanego algorytmu (odnotowanego w RFC wymienionym na stronie projektu open source), a implementacje authenticator obsługują wiele kont.

Rzeczywisty proces jest prosty. Kod jednorazowy jest zasadniczo pseudo generatorem liczb losowych. Generator liczb losowych jest formułą, która po podaniu ziarna lub liczby startowej nadal tworzy strumień liczb losowych. Podane ziarno, podczas gdy liczby mogą być losowe dla siebie, sama sekwencja jest deterministyczna. Tak więc, gdy Twoje urządzenie i serwer będą "zsynchronizowane", losowe liczby, które urządzenie tworzy, za każdym razem, gdy naciśniesz przycisk" Następny numer", będą tymi samymi, losowymi liczbami, których oczekuje serwer.

Bezpieczny system haseł jednorazowych jest bardziej wyrafinowany niż generator liczb losowych, ale koncepcja jest podobna. Istnieją również inne szczegóły, które pomagają utrzymać synchronizację urządzenia i serwera.

Więc, nie ma potrzeby, aby ktoś inny obsługiwał uwierzytelnianie, na przykład OAuth. Zamiast tego musisz zaimplementować ten algorytm, który jest kompatybilny z aplikacjami udostępnianymi przez Google na urządzeniach mobilnych. To oprogramowanie jest (powinno być) dostępne w projekcie open source.

W zależności od zaawansowania, powinieneś mieć wszystko, czego potrzebujesz, aby zaimplementować stronę serwera tego procesu, podać projekt OSS i RFC. Nie wiem czy jest jakaś konkretna implementacja dla Twojego oprogramowania serwerowego (PHP, Java,. NET, itp.)

Ale, w szczególności, nie potrzebujesz usługi poza siedzibą, aby to załatwić.

 112
Author: Will Hartung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-23 04:44:11

Algorytm jest udokumentowany w RFC6238 . Idzie trochę tak:

  • Twój serwer daje użytkownikowi sekret do zainstalowania w Google Authenticator. Google robi to jako kod QR tutaj .
  • [5]} Google Authenticator generuje 6-cyfrowy kod z SHA1-HMAC czasu uniksowego i tajemnicy (o wiele więcej szczegółów na ten temat w RFC)
  • serwer zna również sekretny / uniksowy czas na weryfikację 6-cyfrowego kodu.

I ' ve had a play implementacja algorytmu w javascript tutaj: http://blog.tinisles.com/2011/10/google-authenticator-one-time-password-algorithm-in-javascript/

 47
Author: russau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-10 01:36:34

Istnieje wiele bibliotek dla PHP (stos LAMP)

PHP

Https://code.google.com/p/ga4php/

Http://www.idontplaydarts.com/2011/07/google-totp-two-factor-authentication-for-php/

Powinieneś być ostrożny przy implementacji auth dwuskładnikowego, musisz upewnić się, że zegary na serwerze i kliencie są zsynchronizowane, że istnieje ochrona przed atakami brute-force na token i że początkowy zalążek używany jest odpowiednio duży.

 20
Author: James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-31 14:13:24

Możesz użyć mojego rozwiązania , zamieszczonego jako odpowiedź na moje pytanie (jest Pełny kod Pythona i Wyjaśnienie):

Implementacja Google Authenticator w Pythonie

Wydaje mi się, że dość łatwo jest zaimplementować go w PHP lub perlu. Jeśli masz z tym jakieś problemy, daj mi znać.

Umieściłem również mój kod na GitHub jako moduł Pythona.

 9
Author: Tadeck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:32

Znalazłem to: https://github.com/PHPGangsta/GoogleAuthenticator . Przetestowałem go i działa dobrze dla mnie.

 6
Author: user1893983,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-29 13:12:20

Theres: https://www.gauthify.com który oferuje go jako usługę

 4
Author: NoviceCoding,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-16 00:59:22

Tak, nie potrzebujesz usługi sieciowej, ponieważ aplikacja Google Authenticator nie komunikuje się z serwerem google, po prostu synchronizuje się z sekretem inicjacyjnym generowanym przez serwer(wprowadzanie do telefonu z kodu QR) podczas upływu czasu.

 2
Author: diyism,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-17 16:59:38

Nie LAMP ale jeśli używasz C# to jest to kod którego używam:

Kod pochodzi z:

Https://github.com/kspearrin/Otp.NET

Klasa Base32Encoding pochodzi z tej odpowiedzi:

Https://stackoverflow.com/a/7135008/3850405

Przykładowy program:

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");
    }

}
 2
Author: Ogglas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-27 08:36:59
 1
Author: briankip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-12 16:15:34