QR Codes And Security: A Shallow Dive

January 29, 2020
Written by

QR-codes-security-shallow-dive

QR codes have been referred to as “robot barf.” Which is too bad, because they’re pretty fascinating if you take a closer look.

In this post, you’ll learn about:

  • History and inner workings of QR codes
  • Use cases and risks
  • How to generate QR codes in your application
  • How QR codes are used for two-factor authentication

QR codes 101

QR code is an abbreviation for Quick Response code. They’re a type of two-dimensional, or “matrix” barcode which means that information is stored across both the horizontal and vertical axes.

QR codes were invented in Japan during 1994. They were originally used for tracking automobile parts. QR codes could store more data than UPC barcodes (the kind you commonly see on grocery store products and such), so they started to catch on in other industries as well. Denso Wave, the company that invented QR codes, made the spec publically available to further increase their use.

How do QR codes actually work?

To decode a QR code image, first the scanning software locates the three distinct squares at the corners of the image.

a QR code with the three large squares in the top left, top right, and bottom left corners circled in pink.

There is a smaller square near the fourth corner which normalizes the image for angle, size, and orientation.

a QR code with the small square near the bottom right corner circled in pink.

Then the tiny dots throughout the image are converted to binary numbers, or characters, depending on the specified encoding.

You can store up to a maximum of 3kb of data in a QR code, although less if you crank up the error checking precision level. Error checking is done via Reed-Solomon code scanning, so that the QR code can still be read if some information is degraded. Reed-Solomon code scanning is incredibly useful. It also corrects errors on CDs, and even the images sent on the Voyager space probe.

Use cases for QR codes

There are loads of use cases for QR codes:

  • adding contact info to a mobile device
  • contactless payment
  • opening a URL
  • scanning secrets to generate time-based one-time passwords
  • alternate reality gaming
  • connecting to a wireless network without having to type in a password
  • people are even putting them on graves

Risks of QR codes

QR codes are handy, but like any useful tool they’re not without risks. Since people can’t tell what a QR code contains with their eyeballs alone, it’s easy to send users to malicious URLs. A security researcher even created a QR code in 2012 that wiped all data on a Samsung phone. Yikes! As always, security research doesn’t perfectly represent real-life risks. Most QR scanner apps now offer users a preview of the URL and allow them the option to click through. Nevertheless, some caution is warranted when scanning random QR codes you find in the wild.

Generating QR codes in your Node.js application

QR encoding is complicated. Unless you are some sort of signal processing whiz, I would not recommend creating your own QR code generator from scratch.

Diagram showing how a QR code is separated into "codewords", including which bits are significant and which areas are used for error correction.

"QR Codeword Ordering" by bobmath is licensed under CC0

Good news: if you’re using a common programming language, there’s probably already a library for that.

For example, in Node.js, node-qrcode is a great util.

Assuming you’ve got a JavaScript dev environment set up, run npm install qrcode from the command line to install the library locally.

From there, you can generate an image file with the following code snippet:

const QRCode = require('qrcode');

const generateQR = async text => {
    try {
        await QRCode.toFile('./qr-code.png', text);
    } catch (err) {
        console.error(err);
    }
}
generateQR('https://bit.ly/37ESIt4/');

After running that file from the command line, open qr-code.png in your file explorer. It should look like this:

a QR code that sends you to https://bit.ly/37ESIt4.

Try scanning the QR code with your phone to validate that it sends you to the correct URL.

node-qrcode offers tons of options for generating different flavors of QR codes. Check out the docs for details.

Using QR codes for 2-factor authentication

Multi-factor authentication is a way of adding extra layers of security in your application. In addition to a password, users must also enter additional data in order to log in. The user can use a One-Time Password (OTP) that is generated by the server and sent to the user over any communication channel: SMS, email, push notification, carrier pigeons, etc.

Alternatively, OTPs can be created on the user’s device. This approach is known as TOTP, which stands for Time-based OTP. The generated passwords, which can also be called tokens, expire after a certain period of time.

screenshot from Authy, an authentication app, showing a TOTP token for Eurobank that expires in 20 seconds.

TOTP works without Internet connectivity since the client and server can generate the tokens without talking to one another. Although, if you lack connectivity and you’re trying to authenticate to a remote server, you’re probably gonna have a bad time. Also, clock drift is real. If your client can’t talk to the internet to maintain clock accuracy eventually the tokens may drift out of sync.

The first step to TOTP authentication is creating a secret key on the server side. That key needs to be sent to the client somehow. Secure keys are pretty long, so typing in the whole thing wouldn’t be fun. That’s where QR codes come in. Many phones have a camera, so the camera can take a photo of the QR code and decode the secret key from the photo.

Then both the client and server can create one time passwords, using the secret key, a cryptographic hashing algorithm, and a timestamp. The key and the timestamp are used as inputs to generate an output from the hashing algorithm. The output of the hashing algorithm is way long. The TOTP standard specifies how to truncate the output into a token short enough to actually type.

The good news is that many apps and APIs already exist for TOTP, such as Authy. You shouldn’t need to roll your own. Authy even supports PII-less registration using QR codes.

What’s next?

Today you’ve learned a little more about QR codes and security. Hopefully some of this has been useful, or at least interesting. There are so many levels of beautiful complexity hidden in things we might otherwise take for granted.

If you’d like to learn more about authentication, check out this post about integrating 2FA into your Python app.