fbmessenger

"an ideal is an idea that you have fallen in love with", Bob Proctor

binance login qr

 

Log in with QR code is a practical login approach to the classic username and password. How does this method work exactly and is it as secure as we think it is? On this article we explore the technology behind QR code login which seems to be taking over many technologically advanced sites such as cryptocurrecy exchanges. Please note that I will not be presenting the specific approach used by any one platform but the QR login concept general.

OK, so to begin, let's first discuss the QR login process.

A user follows the below steps to login on the browser:

1. Visits the platform website that provides the login screen with the QR code login option.

2. The user opens the relevant app on their phone that has the capability to provide the 'scan to login' option

3. User scans the QR code displayed

4. The user clicks authorize on the phone app to allow the new device, in this instance the browser they are trying to login to

5. The web client page refreshes to the deisgnated 'Home' page which is usually displayed following a successful login

As a rule of thumb, for a browser to be in a logged in state, a session id is stored, as a cookie, in a browser. Every time a request is made to the server by the client, the browser/app is instructed to send the session id together with that request.

diagram Web Sessions

So essentially, once a user scans the QR code on a browser, they either share their session id from their logged in app, or they instruct the server to create a new authenticated session id and assign it to the device that initially displayed the QR code.

The technology used behind the user interface on the browsers' side is 'websockets'. This is a form of a TCP connection with a server which typically exchanges messages in the form of JSON strings.

 In this example a client machine sends a request for a QR code image to a server which then sends the QR code back to the client. The image contains a unique identifier for that client machine via the browser. The identifier is also stored on a server which awaits for a message to link that with a session id from an authenticated mobile device.

The mobile device scans the QR code, in the above screenshot example the client id is stored as part of a URL (https://www.binance.com/en/qr/f6a71b7736d74ba59fca478f77d7ef9c). The authenticated device then sends their session id to the server and requests that the client with the above id is granted either the same or a new session id.

The technical aspect.

For our simple example we will use:

  • a webserver which will host our angularjs client side.
  • a PHP webserver which will generate a QR code as an image based on the request by the client.
  • a websocket server which the client will connect to and await for any incoming messages
  • a webserver which will save the mappings between an authenticated client and a new client

 Webserver to host the Angularjs client (index.html):

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/gdi2290/angular-websocket@v1.0.9/angular-websocket.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-sanitize.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<div ng-app="MyAwesomeApp" ng-controller="MyCtrl">

<h1><p ng-bind-html="msg"></p> {{serveraddr}}:{{serverport}}</h1>
<div ng-show="!authenticated">
<img style="width: 250px; height: 250px;" ng-src="data:image/png;base64,{{imgsrc}}"/>
</div>
<hr />
<div ng-show="authenticated">
Authenticated with phone scan app.
</div>
</div>
</body>
<script src="/app.js"></script>
</html>

Webserver to host the Angularjs client (app.js):

'use strict';

 var app = angular.module('MyAwesomeApp', ['angular-websocket', 'ngSanitize']);

 app.controller('MyCtrl', function ($scope, $websocket, $http) {

let uid = Math.floor(Math.random() * 100000) +1000;
var vm = this;

$http.get("LoginLess_QR.php?uid="+uid)
.then(function(response) {
console.log(response);

let uid_data = response.data;
$scope.imgsrc = uid_data.imgsrc;
vm.openConnection();
});


$scope.ws = $websocket();
$scope.serveraddr = 'ws://192.168.2.27';
$scope.serverport = '8082';
$scope.messageInputBox = '{"client_id":"'+uid+'"}';

$scope.msg = "click to connect...";

$scope.authenticated = false;

vm.closeConnection = function() {
console.log('Closing from client connection with state ' + $scope.ws.readyState);
//$scope.data = '{"close_connection": "true"}';
$scope.data = 'bye';
if($scope.ws.readyState != $websocket.CLOSED) {
$scope.ws.send($scope.data);
$scope.ws.close();
}
};

vm.openConnection = function() {
$scope.msg = '<i class="fa fa-refresh fa-spin" style="font-size:24px"></i>';
console.log('Opening connection...');

$scope.ws = $websocket($scope.serveraddr+':'+$scope.serverport)
.onOpen(function(message){

vm.logMessage('connected to...');
$scope.msg = 'Connected';
console.log('connected...' + JSON.stringify(message));

vm.sendMessage();

})
.onClose(function(message){

$scope.msg = 'connection closed with...';
console.log('connection closed...' + JSON.stringify(message));
})
.onMessage(function(message){
console.log(message);
let ws_incoming = JSON.parse(message.data);

if(ws_incoming.authkey_data.includes("AUTH_")){
$scope.authenticated = true;
}
//let parsed_data = JSON.parse(incomingData.uid);

let authkey_data = JSON.parse(ws_incoming.authkey_data);
//$scope.msg = "GOT KEY: " + authkey_data.authkey; //optionally show the received key
$scope.msg = '<i class="fa fa-check" style="color: green; font-size:24px"></i>';
console.log("GOT KEY: " + authkey_data.authkey);

});

};

vm.sendMessage = function() {
console.log('Sending message');
$scope.data = $scope.messageInputBox;
$scope.ws.send($scope.data);
};

vm.logMessage = function(aMsg){
$scope.msg = aMsg;
};

});

PHP Server script to provide the QR code as an base 64 encoded image(LoginLess_QR.php):

<?php

date_default_timezone_set("Europe/Nicosia");

if (isset($_GET['uid'])) {

include "qrlib.php";

$QRC_LOCAL_URL = "";
$errorCorrectionLevel = 'L';
$matrixPointSize = 4;

define('IMAGE_WIDTH',150);
define('IMAGE_HEIGHT',150);

$trnData['uid'] = intval($_GET['uid']);

$imageData = $QRC_LOCAL_URL.$trnData['uid'];

ob_start();
QRCode::png($imageData, null);
$imageString = base64_encode( ob_get_contents() );
ob_end_clean();

echo json_encode(array('uid'=>$imageData, 'imgsrc'=>$imageString));

}
else
{
echo 'NaN';
}

?>

PHP Server script to save the mapping between an authenticated client and a new client as a new file (LoginLess_Mapping.php):

<?php
if (isset($_GET['u']) && intval($_GET['u']) > 0 && intval($_GET['u']) < 100000) {
$file_to_write = intval($_GET['u']).'.txt';
$data_to_file = '{"authkey":"AUTH_000_'.intval($_GET['u']).'"}';
echo file_put_contents( $file_to_write, $data_to_file );
}
?>

Websocket Server that exchanges messages between a client machine and checks for any authenticated ids to provide (Note that this server was written for an ESP8266):

/**
Websocket Server and HTTP Client.ino

Created on: 26.04.2022

*/

#include <Arduino.h>

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

#include <ESP8266HTTPClient.h>

#include <WiFiClient.h>
#include <ArduinoWebsockets.h>
#include <Arduino_JSON.h>

ESP8266WiFiMulti WiFiMulti;
using namespace websockets;
WebsocketsServer server;

 

void setup() {

Serial.begin(115200);
// Serial.setDebugOutput(true);

Serial.println();
Serial.println();
Serial.println();

for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}

WiFi.mode(WIFI_STA);

WiFiMulti.addAP("SSID", "PASSWORD");

Serial.print("Connecting to WiFi ..");
while (WiFiMulti.run() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}


Serial.println("IP address: ");
Serial.println(WiFi.localIP()); //You can get IP address assigned to ESP

server.listen(8082);
Serial.print("Is server live? ");
Serial.println(server.available());

}

void loop() {

 

WebsocketsClient clientsv = server.accept();

while(clientsv.available()) {
WebsocketsMessage msg = clientsv.readBlocking();


// log
Serial.print("Got Message: ");
Serial.println(msg.data());
// blinkLight(2);


String received_data = msg.data();

JSONVar incomingRequest = JSON.parse(received_data);

if (incomingRequest.hasOwnProperty("client_id")) {

String uid = "";
int countTries = 0;


uid = retrieveHTTPData((const char*) incomingRequest["client_id"]);
//keep checking up to 12 seconds, modify according to your needs or just remove the second part of the if statement
while(uid == "" && countTries < 12){

//wait 1 second and try again
delay(1000);
Serial.println("Attempting to retrieve key " + countTries);
uid = retrieveHTTPData((const char*) incomingRequest["client_id"]);

countTries++;

}

if(uid != "") {
JSONVar outgoingRequest;

outgoingRequest["client_id"] = (const char*) incomingRequest["client_id"];
outgoingRequest["authkey_data"] = uid;



Serial.print("outgoingRequest.keys() = ");
Serial.println(outgoingRequest.keys());

// Send the message to the client with the found id key
String jsonString = JSON.stringify(outgoingRequest);
clientsv.send(jsonString);
delay(100);

Serial.println("Closing connection with client");
// close the connection
clientsv.close();
}
}

if(incomingRequest.hasOwnProperty("close_connection")){

Serial.println("Closing connection with client");
// close the connection
clientsv.close();
//to do delete mapping from db by sending relevant request
}

}

delay(50);

}

String retrieveHTTPData(String uid){

WiFiClient client;

HTTPClient http;
Serial.print("[HTTP] begin...\n");

if (http.begin(client,
//"http://serveraddress/LoginLess_Mapping.php?uid=" + uid)
"http://serveraddress/" + uid + ".txt")
){ // HTTP

Serial.println("Getting key from http://serveraddress/" + uid + ".txt");

Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();

// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\n", httpCode);

// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = http.getString();
Serial.println(payload);
return payload;
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());

}

http.end();
return "";
} else {
Serial.printf("[HTTP} Unable to connect\n");
return "";
}
}

Our Values

Mission: Our mission is to help our customers achieve their target goals and increase their profitability by fully maximizing the potential of their web presence.

Vision: To lead the industry with the technical advantage and help our customers succeed financially.

Values: Ethics, Customer Centrism, Integrity, Reliability, Team Spirit and Accountability.

Services

What we offer


Web Development

A Professional Website for your Business

Web Applications

Such as an Online Booking form, a Signup form or a Customer Satisfaction Survey form

Mobile Apps

Utilize Smartphone Features such as the Camera and the Geo-Location



Software Development

Solutions for Computers on all the Platforms, Mac, Linux and Windows

eCommerce

Solutions for Online Merchants

CRM

Customer Relationship Management

Portfolio - Website Development

 

A Sample of Our Work

Paris

WindowRama Vinyl Ltd

Complete Prefabricated Homes and Guttering Systems

New York

GAH Global

Biogas and Waste Water Treatment Plant Contractor

San Francisco

Amadeus Holidays

Walking-Holidays Tour Operator

Athanasiou Insurance Agents and Consultants

Athanasiou Insurance Agents and Consultants

Insurance Agency and Consultancy Services