Привет Хабр! Недавно понадобилось интегрировать соц. сеть в проекте для Android. Выбор пал на ВК и, соотвественно, их офиц.библиотеку VKCOM/vk-android-sdk. Использовал ее раньше и ещё тогда не был от неё в восторге из-за малого количества примеров. Сейчас смотрю в исходный код, а он всё также далеко не идеален.

Обычно всегда просматриваю ключи в преференсах при запуске приложения и увидел такое вот (после авторизации):

Ключ: VK_SDK_ACCESS_TOKEN_PLEASE_DONT_TOUCH
Значение: scope=offline&https_required=1&access_token=e5cd068be722caafd3c449557e19c19eeed3f54c295a65cd097ed087f61c44394bd985975364fc34641cc&expires_in=0&created=1476876628588&user_id=220436550

Насторожило. Не думаю, что это хорошо хранить такие данные в открытом виде. Вообще, ещё после первого знакомства думал о возможности считывания вводимых данных при авторизации. Почему бы нет?

Нужно всего лишь импортировать как модуль. Убираем возможность авторизации через основного клиента (оставляем второй вариант):

if (VKUtil.isAppInstalled(ctx, VK_APP_PACKAGE_ID)
    && VKUtil.isIntentAvailable(ctx, VK_APP_AUTH_ACTION)
    && fingerprints.length > 0
    && fingerprints[0].equals(VK_APP_FINGERPRINT)) {
        if (savedInstanceState == null) {
            intent = new Intent(VK_APP_AUTH_ACTION, null);
            intent.setPackage(VK_APP_PACKAGE_ID);
	    intent.putExtras(bundle);
	    startActivityForResult(intent, VKServiceType.Authorization.getOuterCode());
        }
    } else {
        new VKOpenAuthDialog().show(this, bundle, VKServiceType.Authorization.getOuterCode(), null);
}

» Исходник здесь

Немного модернизируем их кастомный webview:

@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
    return new BaseInputConnection(this, false);
}

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    super.dispatchKeyEvent(event);
    // Без условия event дублируется
    if (event.getAction() == KeyEvent.ACTION_UP) {
        Log.d("TAG", event.getKeyCode() + " | " + event.toString());
    }
    return true;
}

» Исходник здесь

Спасибо ответу на StackOverFlow. Получается пароль и логин полностью считывается при ручном вводе в их диалоговом окошке (без копипаста). Можно определить даже регистр символа:

Вывод logcat
7 | KeyEvent { action=ACTION_UP, keyCode=KEYCODE_0, ..., source=0x0 }
59 | KeyEvent { action=ACTION_UP, keyCode=KEYCODE_SHIFT_LEFT, ..., source=0x0 }
40 | KeyEvent { action=ACTION_UP, keyCode=KEYCODE_L, ..., source=0x0 }

Всё это открывает широкие возможности. Возможно ещё можно подобрать схожие примеры.
Я небольшой спец в cookies, но, например, удается вытащить поля remixstid, remixmdevice, remixlang, remixlhk. Похоже они касаются данных о токене, судя по описанию функции выхода для аккаунта в основном классе.

/**
  * Wipes out information about the access token and clears cookies for internal browse
  */
@SuppressLint("NewApi")
public static void logout() {
    ...
    CookieManager.getInstance().removeAllCookies(null);
    ...
}

» Исходник здесь

Думаю для ВК лучше полностью перенести авторизацию на основного клиента. А что касаемо API, наполнить подробными примерами (Wiki на GitHub неплох в дополнение javadoc имеющемуся). Но сейчас использовать такой подход сомнительно.

Спасибо за внимание!
Поделиться с друзьями
-->

Комментарии (11)


  1. Valle
    19.10.2016 18:40

    1) Т.е. предлагаете ключи зашифровать, правильно? А ключ шифрования где хранить будете?
    2) Можно поподробнее про широкие возможности логгирования?


    1. mr-cpp
      19.10.2016 19:02

      1) Можно было бы. Например, в одном приложении я шифровал пароль с логином через AES. Но опять же исходники открыты (впрочем и без этого они открыты можно сказать, но на гитхабе все очень читаемо). Поэтому думаю это обязанность или разработчиков отдельно, или уже команды вк (будь-то хранить на серверах как и сейчас и/или расширить возможности своего клиента, где возможно использовать шифрование). Но точно не такой способ как сейчас.
      2) Это я в смысле несанкционированного доступа к аккаунту вк.
      Думаю, неплох вариант, когда приложение обращалось бы к клиенту за токеном. И получается напрямую разработчикам было бы доступно непосредственно только обращение к API.


  1. Valle
    20.10.2016 06:25
    +1

    1) Это вполне нормальный способ. Единственный метод добыть ключи из приватных файлов атакуещему когда все остальное не дырявое — это добыть файлы из под рута. Но когда у тебя рут то можно вообще все сделать.
    2) Та же самая штука — зачем самому себя хакать? Если SDK это часть своего приложения то с любыми процессами в своем приложении можно сделать что угодно любыми методами. А другим приложениям эти данные недоступны.


    1. mr-cpp
      20.10.2016 12:17

      Согласен с Вами во многом. Но мы говорим об sdk, которой пользуются тысячи людей.
      Существует много вредоносных программ, способные собрать таким образом токены, а сотням недобросовестных разработчиков под силу получить доступ к персональной информации своего пользователя.


      1. mityal
        20.10.2016 14:53

        Точно так же вы могли создать WebView где открывалась бы фишинговая страница.


        1. mr-cpp
          20.10.2016 15:36

          Впринципе да. Но это трудоемко. И все-таки это не сама цель статьи. Я хотел указать на недостатки библиотеки больше


          1. Valle
            20.10.2016 17:56
            +1

            Так а недостатки в чем? Что вредоносные программы могут взять этот sdk и им пользоваться для сбора данных пользователей?


            1. mr-cpp
              20.10.2016 18:05

              Могут вполне. Недостатки: 1. Открытое хранение токенов. 2. Использование webview в sdk для авторизации. Стоит от этого отказаться. Ну и остальное явно/неявно является следствием этих двух.


              1. Valle
                22.10.2016 19:50

                Т.е. если хранить токен как aes(plainTextToken, «supersecretkey») а webview заменить на активити то считаете это существенно что-то изменит? Я думаю нет, т.к. токен все равно можно достать с одним несложным дополнительным шагом (а если нельзя то и хранить его незачем), а любые события ввода можно и из активити достать точно так же как и их вебвьюхи.


  1. Sixshaman
    21.10.2016 01:12

    О, наконец-то кто-то, кто тоже страдает от VK Android SDK!

    Удивляет то, что в этом SDK довольно скудная документация. Скажем, взять ту же авторизацию. Единственное, что написано в официальной документации — это то, что нужно использовать метод VKSdk.login(), в который передаётся параметр scope. Ни примеров, каким может быть scope, ни хотя бы объяснения, что он значит, в документации нет. Приходится лезть в исходники и уже там видеть, что это массив разрешений. Но списка возможных значений нет нигде вообще.

    Или, например, открытие официального приложения VK из своего Android-приложения. Скажем, чтобы открыть чей-то профиль, нужно создать следующий интент:

    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("vkontakte://profile/" + friendID));

    А теперь нетривиальная задачка: как открыть чат с человеком c ID friendID?


    1. mr-cpp
      21.10.2016 07:22

      Верно. Кажется, по этой причине, удобнее api sdk заменять на rest запросы (тем более часто не все же нужно, только общую информацию, публикации стены и т.д.)


      Но списка возможных значений нет нигде вообще.

      Они здесь)
      С клиентом не работал, похоже это боль)