• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..15-Oct-2020-

src/H15-Oct-2020-702391

LICENCE.mdH A D15-Oct-20201.3 KiB2620

README.mdH A D15-Oct-202016.8 KiB474325

composer.jsonH A D15-Oct-2020432 1817

README.md

1# U2F-php-server
2
3[![Latest Stable Version](https://img.shields.io/packagist/v/samyoul/u2f-php-server.svg?style=flat-square)](https://packagist.org/packages/samyoul/u2f-php-server)
4[![License](https://img.shields.io/badge/license-BSD_2_Clause-brightgreen.svg?style=flat-square)](LICENCE.md)
5
6Server-side handling of FIDO U2F registration and authentication for PHP.
7
8Securing your online accounts and doing your bit to protect your data is extremely important and increasingly more so as hackers get more sophisticated.
9FIDO's U2F enables you to add a simple unobtrusive method of 2nd factor authentication, allowing users of your service and/or application to link a hardware key to their account.
10
11## The Family of U2F php Libraries
12
13**Base Library**
14
15https://github.com/Samyoul/U2F-php-server
16
17**Fido Test Suite (UTD)**
18
19https://github.com/Samyoul/U2F-php-UTD
20
21**Frameworks**
22
23*Laravel* https://github.com/Samyoul/U2F-Laravel-server
24
25*Yii* https://github.com/Samyoul/U2F-Yii-server
26
27*CodeIgniter* https://github.com/Samyoul/U2F-CodeIgniter-server
28
29
30## Contents
31
321. [Installation](#installation)
332. [Requirements](#requirements)
34    1. [OpenSSL](#openssl)
35    1. [Clientside Magic](#client-side-the-magic-javascript-bit-of-talking-with-a-usb-device)
36    1. [HTTPS and SSL](#https-and-ssl)
373. [Terminology](#terminology)
384. [Recommended Datastore Structure](#recommended-datastore-structure)
395. [Process Workflow](#process-workflow)
40    1. [Registration Process Flow](#registration-process-flow)
41    1. [Authentication Process Flow](#authentication-process-flow)
426. [Example Code](#example-code)
43    1. [Compatibility Check](#compatibility-code)
44    1. [Registration Code](#registration-code)
45    1. [Authentication Code](#authentication-code)
467. [Frameworks](#frameworks)
47    1. [Laravel](#laravel-framework)
48    1. [Yii](#yii-framework)
49    1. [CodeIgniter](#codeigniter-framework)
508. [Licence](#licence)
519. [Credits](#credits)
52
53## Installation
54
55`composer require samyoul/u2f-php-server`
56
57## Requirements
58
59A few **things you need** to know before working with this:
60
611. [**_OpenSSL_**](#openssl) You need at least OpenSSL 1.0.0 or higher.
622. [**_Client-side Handling_**](#client-side) You need to be able to communicate with a some kind of device.
633. [**_A HTTPS URL_**](#https-and-ssl) This is very important, without HTTPS U2F simply will not work.
644. [**_A Datastore_**](#recommended-datastore-structure) You need some kind of datastore for all your U2F registered users (although if you have a system with user authentication I'm presuming you've got this one sorted).
65
66### OpenSSL
67
68This repository requires OpenSSL 1.0.0 or higher. For further details on installing OpenSSL please refer to the php manual http://php.net/manual/en/openssl.installation.php .
69
70Also see [Compatibility Code](#compatibility-code), to check if you have the correct version of OpenSSL installed, and are unsure how else to check.
71
72### Client-side (The magic JavaScript Bit of talking with a USB device)
73
74My presumption is that if you are looking to add U2F authentication to a php system, then you'll probably are also looking for some client-side handling. You've got a U2F enabled USB device and you want to get the USB device speaking with the browser and then with your server running php.
75
761. Google already have this bit sorted : https://github.com/google/u2f-ref-code/blob/master/u2f-gae-demo/war/js/u2f-api.js
772. [Mastahyeti](https://github.com/mastahyeti) has created a repo dedicated to Google's JavaScript Client-side API : https://github.com/mastahyeti/u2f-api
78
79### HTTPS and SSL
80
81For U2F to work your website/service must use a HTTPS URL. Without a HTTPS URL your code won't work, so get one for your localhost, get one for your production. https://letsencrypt.org/
82Basically encrypt everything.
83
84
85## Terminology
86
87**_HID_** : _Human Interface Device_, like A USB Device [like these things](https://www.google.co.uk/search?q=fido+usb+key&safe=off&tbm=isch)
88
89## Recommended Datastore Structure
90
91You don't need to follow this structure exactly, but you will need to associate your Registration data with a user. You'll also need to store the key handle, public key and the certificate, counter isn't 100% essential but it makes your application more secure.
92
93
94|Name|Type|Description|
95|---|---|---|
96|id|integer primary key||
97|user_id|integer||
98|key_handle|varchar(255)||
99|public_key|varchar(255)||
100|certificate|text||
101|counter|integer||
102
103TODO the descriptions
104
105## Process Workflow
106
107### Registration Process Flow
108
1091. User navigates to a 2nd factor authentication page in your application.
110
111... TODO add the rest of the registration process flow ...
112
113### Authentication Process Flow
114
1151. User navigates to their login page as they usually would, submits username and password.
1161. Server received POST request authentication data, normal username + password validation occurs
1171. On successful authentication, the application checks 2nd factor authentication is required. We're going to presume it is, otherwise the user would just be logged in at this stage.
1181. Application gets the user's registered signatures from the application datastore: `$registrations`.
1191. Application gets its ID, usually the domain the application is accessible from: `$appId`
1201. Application makes a `U2F::makeAuthentication($registrations, $appId)` call, the method returns an array of `SignRequest` objects: `$authenticationRequest`.
1211. Application JSON encodes the array and passes the data to the view
1221. When the browser loads the page the JavaScript fires the `u2f.sign(authenticationRequest, function(data){ // Callback logic })` function
1231. The view will use JavaScript / Browser to poll the host machine's ports for a FIDO U2F device
1241. Once the HID has been found the JavaScript / Browser will send the sign request with data.
1251. The HID will prompt the user to authorise the sign request
1261. On success the HID returns authentication data
1271. The JavaScript receives the HID's returned data and passes it to the server
1281. The application takes the returned data passes it to the `U2F::authenticate($authenticationRequest, $registrations, $authenticationResponse)` method
1291. If the method returns a registration and doesn't throw an Exception, authentication is complete.
1301. Set the user's session, inform the user of the success, and redirect them.
131
132## Example Code
133
134For a full working code example for this repository please see [the dedicated example repository](https://github.com/Samyoul/U2F-php-server-examples)
135
136You can also install it with the following:
137
138```bash
139$ git clone https://github.com/Samyoul/U2F-php-server-examples.git
140$ cd u2f-php-server-examples
141$ composer install
142```
143
144
1451. [Compatibility Code](#compatibility-code)
1462. [Registration Code](#registration-code)
147    1. [Step 1: Starting](#registration-step-1)
148    1. [Step 2: Talking to the HID](#registration-step-2)
149    1. [Step 3: Validation & Storage](#registration-step-3)
1503. [Authentication Code]()
151    1. [Step 1: Starting]()
152    1. [Step 2: Talking to the HID]()
153    1. [Step 3: Validation]()
154
155---
156
157### Compatibility Code
158
159You'll only ever need to use this method call once per installation and only in the context of debugging if the class is giving you unexpected errors. This method call will check your OpenSSL version and ensure it is at least 1.0.0 .
160
161```php
162<?php
163
164require('vendor/autoload.php');
165use Samyoul\U2F\U2FServer\U2FServer as U2F;
166
167var_dump(U2F::checkOpenSSLVersion());
168```
169
170---
171
172### Registration Code
173
174#### Registration Step 1:
175**Starting the registration process:**
176
177We assume that user has successfully authenticated and wishes to register.
178
179```php
180<?php
181
182require('vendor/autoload.php');
183use Samyoul\U2F\U2FServer\U2FServer as U2F;
184
185session_start();
186
187// This can be anything, but usually easier if you choose your applications domain and top level domain.
188$appId = "yourdomain.tld";
189
190// Call the makeRegistration method, passing in the app ID
191$registrationData = U2F::makeRegistration($appId);
192
193// Store the request for later
194$_SESSION['registrationRequest'] = $registrationData['request'];
195
196// Extract the request and signatures, JSON encode them so we can give the data to our javaScript magic
197$jsRequest = json_encode($registrationData['request']);
198$jsSignatures = json_encode($registrationData['signatures']);
199
200// now pass the data to a fictitious view.
201echo View::make('template/location/u2f-registration.html', compact("jsRequest", "jsSignatures"));
202```
203
204#### Registration Step 2:
205**Client-side, Talking To The USB**
206
207Non-AJAX client-side registration of U2F key token. AJAX can of course be used in your application, but it is easier to demonstrate a linear process without AJAX and callbacks.
208
209```html
210<html>
211<head>
212    <title>U2F Key Registration</title>
213</head>
214<body>
215    <h1>U2F Registration</h1>
216    <h2>Please enter your FIDO U2F device into your computer's USB port. Then confirm registration on the device.</h2>
217
218    <div style="display:none;">
219        <form id="u2f_submission" method="post" action="auth/u2f-registration/confirm">
220            <input id="u2f_registration_response" name="registration_response" value="" />
221        </form>
222    </div>
223
224<script type="javascript" src="https://raw.githubusercontent.com/google/u2f-ref-code/master/u2f-gae-demo/war/js/u2f-api.js"></script>
225<script>
226    setTimeout(function() {
227
228        // A magic JS function that talks to the USB device. This function will keep polling for the USB device until it finds one.
229        u2f.register([<?php echo $jsRequest ?>], <?php echo $jsSignatures ?>], function(data) {
230
231            // Handle returning error data
232            if(data.errorCode && errorCode != 0) {
233                alert("registration failed with error: " + data.errorCode);
234                // Or handle the error however you'd like.
235
236                return;
237            }
238
239            // On success process the data from USB device to send to the server
240            var registration_response = JSON.stringify(data);
241
242            // Get the form items so we can send data back to the server
243            var form = document.getElementById('u2f_submission');
244            var response = document.getElementById('u2f_registration_response');
245
246            // Fill and submit form.
247            response.value = JSON.stringify(registration_response);
248            form.submit();
249        });
250    }, 1000);
251</script>
252</body>
253</html>
254```
255
256#### Registration Step 3:
257**Validation and Key Storage**
258
259This is the last stage of registration. Validate the registration response data against the original request data.
260
261```php
262<?php
263
264require('vendor/autoload.php');
265use Samyoul\U2F\U2FServer\U2FServer as U2F;
266
267session_start();
268
269// Fictitious function representing getting the authenticated user object
270$user = getAuthenticatedUser();
271
272try {
273
274    // Validate the registration response against the registration request.
275    // The output are the credentials you need to store for U2F authentication.
276    $validatedRegistration = U2F::register(
277        $_SESSION['registrationRequest'],
278        json_decode($_POST['u2f_registration_response'])
279    );
280
281    // Fictitious function representing the storing of the validated U2F registration data against the authenticated user.
282    $user->storeRegistration($validatedRegistration);
283
284    // Then let your user know what happened
285    $userMessage = "Success";
286} catch( Exception $e ) {
287    $userMessage = "We had an error: ". $e->getMessage();
288}
289
290//Fictitious view.
291echo View::make('template/location/u2f-registration-result.html', compact('userMessage'));
292```
293
294---
295
296### Authentication Code
297
298#### Authentication Step 1:
299**Starting the authentication process:**
300
301We assume that user has successfully authenticated and has previously registered to use FIDO U2F.
302
303```php
304<?php
305
306require('vendor/autoload.php');
307use Samyoul\U2F\U2FServer\U2FServer as U2F;
308
309session_start();
310
311// Fictitious function representing getting the authenticated user object
312$user = getAuthenticatedUser();
313
314// Fictitious function, get U2F registrations associated with the user
315$registrations = $user->U2FRegistrations();
316
317// This can be anything, but usually easier if you choose your applications domain and top level domain.
318$appId = "yourdomain.tld";
319
320// Call the U2F makeAuthentication method, passing in the user's registration(s) and the app ID
321$authenticationRequest = U2F::makeAuthentication($registrations, $appId);
322
323// Store the request for later
324$_SESSION['authenticationRequest'] = $authenticationRequest;
325
326// now pass the data to a fictitious view.
327echo View::make('template/location/u2f-authentication.html', compact("authenticationRequest"));
328```
329
330#### Authentication Step 2:
331**Client-side, Talking To The USB**
332
333Non-AJAX client-side authentication of U2F key token. AJAX can of course be used in your application, but it is easier to demonstrate a linear process without AJAX and callbacks.
334
335
336```html
337<html>
338<head>
339    <title>U2F Key Authentication</title>
340</head>
341<body>
342    <h1>U2F Authentication</h1>
343    <h2>Please enter your FIDO U2F device into your computer's USB port. Then confirm authentication on the device.</h2>
344
345    <div style="display:none;">
346        <form id="u2f_submission" method="post" action="auth/u2f-authentication/confirm">
347            <input id="u2f_authentication_response" name="authentication_response" value="" />
348        </form>
349    </div>
350
351    <script type="javascript" src="https://raw.githubusercontent.com/google/u2f-ref-code/master/u2f-gae-demo/war/js/u2f-api.js"></script>
352    <script>
353    setTimeout(function() {
354
355        // Magic JavaScript talking to your HID
356        u2f.sign(<?php echo $authenticationRequest; ?>, function(data) {
357
358            // Handle returning error data
359            if(data.errorCode && errorCode != 0) {
360                alert("Authentication failed with error: " + data.errorCode);
361                // Or handle the error however you'd like.
362
363                return;
364            }
365
366            // On success process the data from USB device to send to the server
367            var authentication_response = JSON.stringify(data);
368
369            // Get the form items so we can send data back to the server
370            var form = document.getElementById('u2f_submission');
371            var response = document.getElementById('u2f_authentication_response');
372
373            // Fill and submit form.
374            response.value = JSON.stringify(authentication_response);
375            form.submit();
376        });
377    }, 1000);
378    </script>
379</body>
380</html>
381```
382
383#### Authentication Step 3:
384**Validation**
385
386This is the last stage of authentication. Validate the authentication response data against the original request data.
387
388```php
389<?php
390
391require('vendor/autoload.php');
392use Samyoul\U2F\U2FServer\U2FServer as U2F;
393
394session_start();
395
396// Fictitious function representing getting the authenticated user object
397$user = authenticatedUser();
398
399// Fictitious function, get U2F registrations associated with the user
400$registrations = $user->U2FRegistrations();
401
402try {
403
404    // Validate the authentication response against the registration request.
405    // The output are the credentials you need to store for U2F authentication.
406    $validatedAuthentication = U2F::authenticate(
407        $_SESSION['authenticationRequest'],
408        $registrations,
409        json_decode($_POST['u2f_authentication_response'])
410    );
411
412    // Fictitious function representing the updating of the U2F token count integer.
413    $user->updateU2FRegistrationCount($validatedAuthentication);
414
415    // Then let your user know what happened
416    $userMessage = "Success";
417} catch( Exception $e ) {
418    $userMessage = "We had an error: ". $e->getMessage();
419}
420
421//Fictitious view.
422echo View::make('template/location/u2f-authentication-result.html', compact('userMessage'));
423```
424
425---
426
427Again, if you want to just download some example code to play with just install the full working code examples written for this repository please see [the dedicated example repository](https://github.com/Samyoul/U2F-php-server-examples)
428
429You can also install it with the following:
430
431```bash
432$ git clone https://github.com/Samyoul/U2F-php-server-examples.git
433$ cd u2f-php-server-examples
434$ composer install
435```
436
437## Frameworks
438
439### Laravel Framework
440
441See the dedicated repository : https://github.com/Samyoul/U2F-Laravel-server
442
443Installation:
444
445`composer require u2f-laravel-server`
446
447### Yii Framework
448
449See the dedicated repository : https://github.com/Samyoul/U2F-Yii-server
450
451Installation:
452
453`composer require u2f-yii-server`
454
455### CodeIgniter Framework
456
457See the dedicated repository : https://github.com/Samyoul/U2F-CodeIgniter-server
458
459Installation:
460
461`composer require u2f-codeigniter-server`
462
463### Can't see yours?
464
465**Your favourite php framework not in this list? Get coding and submit a pull request and get your framework extension included here.**
466
467## Licence
468
469The repository is licensed under a BSD license. [Read details here](https://github.com/Samyoul/U2F-php-server/blob/master/LICENCE.md)
470
471## Credits
472
473This repo was originally based on the Yubico php-u2flib-server https://github.com/Yubico/php-u2flib-server
474