• Products

    Access

    Improve user conversion, go passwordless.

    Gate

    The identity-aware edge authorizer.

    Data Vault

    Serverless-ready secure PII user data storage.

  • Use cases

    Product

    Onboarding

    Analytics & Screening

    Fraud & Security

    Engineering

    Edge Authentication

    Application Access Plane

  • Developers
  • Blog
  • Gallery

    E-commerce Playground

    Build a passwordless eCommerce experience backed by SlashID.

    Multi-tenant App

    Build a multi-tenant app using SlashID.

Log in
Get started

Products

Access

Gate

Data Vault

Use cases

Onboarding

Analytics & Screening

Fraud & Security

Edge Authentication

Application Access Plane

Developers

Blog

Gallery

E-commerce Playground

Multi-tenant App

Log in
Get started
Tutorial/18 Sep, 2023

No-code anti-phishing protection of internal apps with Passkeys

Phishing is one of the most common causes of data breaches. According to Verizon's DBIR report, over 50% of incidents start with phishing or stolen credentials. WebAuthn/Passkeys are an effective way to stop phishing and credential stealing attempts on their tracks.

In this article, we’ll show how you can use Gate to enforce Passkeys authentication for users without modifying the application code.


Introduction

Phishing is among the most common causes of data breaches. Attackers often trick users into inputing their credentials into websites that look legitimate to the human-eye but are actually setup by the attacker to steal credentials.

While MFA is an effective tool to reduce this kind of attacks, it is unfortunately insufficient. Multiple campaigns in the past have shown how attackers can get around MFA through various techniques.

WebAuthn/Passkeys provide strong protection against phishing attacks. In fact, all compliant browsers enforce a number of security checks that render phishing unfeasible in the majority of scenarioes.

Enforcing access to apps through Passkeys is not always possible as the company might not have access to the source code or might not have the resources to dedicate to the project. Gate is an effective way to easily enforce complex authentication and authorization policies out-of-the-box on web applications without any code changes.

Read on to see an example on how to add fine-grained access control and Passkeys auth to an arbitrary application in 10 minutes or less.

WebAuthn and phishing

WebAuthn/Passkeys are public-private keypairs where only the public key is transmitted to the server, making credential stealing unfeasible unless an attacker compromises a user machine.

Further, the WebAuthn spec and implementations in the browsers have been designed to be phishing-resistant and several checks are in place for an authentication ceremony to happen.

First of all, WebAuthn doesn’t work without TLS. Furthermore, browsers enforce origin checks and most will prevent access to the platform authenticator unless the window is in focus or, in the case of Safari, the user triggers an action.

In other words, an attacker trying to compromise user credentials will need to either find a cross-site scripting (XSS) bug in the target website or a vulnerability in the browser, both of which are very high barriers to overcome. This is the only way in which they can bypass the WebAuthn checks.

In either scenario, a successful attack still won’t give the attacker access to the private key itself, but only to a session token/cookie which will expire once the browsing session is over.

Most importantly, due to the origin checks, most of the recent attacks involving domain squatting and phishing would fall flat because the reverse proxy wouldn’t be able to initiate the WebAuthn authentication process.

In comparison to all other authentication methods — where an attacker only has to register a seemingly related domain and have a similar looking webpage to fool the victim through phishing — it is clear that WebAuthn is a vastly superior authentication method.

The internal app: YouTrack

For this example we are going to assume that we have a self-hosted deployment of YouTrack, the popular issue tracker software. For simplicity, we’ll use docker compose for the deployment but Gate supports several deployment topologies.

version: '3.3'

services:
  youtrack:
    image: jetbrains/youtrack@sha256:<hash>
    container_name: 'youtrack'
    volumes:
      - /mnt/disks/youtrack-data/youtrack/data:/opt/youtrack/data
      - /mnt/disks/youtrack-data/youtrack/conf:/opt/youtrack/conf
      - /mnt/disks/youtrack-data/youtrack/logs:/opt/youtrack/logs
      - /mnt/disks/youtrack-data/youtrack/backups:/opt/youtrack/backups
    expose:
      - '8080'

Deploying Gate

We are going to deploy Gate in front of the application such that Gate can intercept unauthenticated requests and prompt the user to login. Visually, it looks as follows:

Configuration

What the Authentication Proxy plugin does is to intercept HTTP requests and if no valid authentication token is found, Gate injects a login page in front of the application. The user logs in with one of the allowed login methods and is then redirected to the original app (in this case YouTrack).

Once the user has authenticated the first time, future requests are passed to YouTrack transparently.

Here’s what the docker compose looks like:

version: '3.3'

services:
  youtrack:
    image: jetbrains/youtrack@<hash>
    container_name: 'youtrack'
    volumes:
      - /mnt/disks/youtrack-data/youtrack/data:/opt/youtrack/data
      - /mnt/disks/youtrack-data/youtrack/conf:/opt/youtrack/conf
      - /mnt/disks/youtrack-data/youtrack/logs:/opt/youtrack/logs
      - /mnt/disks/youtrack-data/youtrack/backups:/opt/youtrack/backups
    expose:
      - '8080'

  gate:
    container_name: gate
    image: slashid/gate:latest
    command: ['-env']
    hostname: gate
    restart: unless-stopped
    environment:
      - GATE_PORT=80
      - GATE_DEFAULT_TARGET=http://youtrack:8080
      - GATE_LOG_FORMAT=text
      - GATE_LOG_LEVEL=info
      - GATE_HEADERS_FORWARDED_SET_OUTBOUND_X_FORWARDED=true
      - GATE_HEADERS_FORWARDED_PRESERVE_INBOUND_X_FORWARDED=true
      - GATE_PLUGINS_1_TYPE=authentication-proxy
      - GATE_PLUGINS_1_ENABLED=true
      - GATE_PLUGINS_1_PARAMETERS_LOGIN_PAGE_HEADING=Welcome to YouTrack
      - GATE_PLUGINS_1_PARAMETERS_STORE_LAST_HANDLE=true
    env_file:
      - .secret.env
    ports:
      - '80:80'
    depends_on:
      - youtrack

Customizing the login page

The authentication proxy plugin supports a number of customization, as shown in the documentation.

In particular, it is possible to specify the valid authentication methods supported:

login_page_factors:
  - method: 'webauthn'
    options:
      <Factor option>: '<Factor option value>'
  - method: 'oidc'
    options:
      <Another factor option>: '<Another factor option value>'

Creating complex authorization policies

The authentication proxy plugin also allows to out-of-the-box restrict access to users belonging to specific groups. For example, we could restrict access to users belonging to the developers group.

required_groups: ['developers']

But sometimes it might be necessary to enforce more complex policies. For instance, we might want to restrict access to users that belong to certain google groups. To do so, we can combine the OPA plugin with the Authentication Proxy plugin. Let’s see how:

...
    - id: authz_admin_oidc
      type: opa
      enabled: true
      parameters:
        <<: *slashid_config
        policy_decision_path: /authz/allow
        policy: |
          package authz

          import future.keywords.if
          default allow := false

          allow if claims.oidc_tokens[0].oidc_groups[_] == "developers@example.com"

          parseCookies(cookies) = cookie {
              parsed = split(cookies, ";")

              cookie = { k: v |
              	  raw = parsed[_]

                  pair = split(raw, "=")
                  k = trim(pair[0], " ")
                  v = trim(substring(raw, count(sprintf("%s=", [pair[0]])), count(raw)), " ")
              }
          }

          cookies := c if {
              v := input.request.http.headers.Cookie[0]
              c := parseCookies(v)
          }

          claims := payload if {
              [_, payload, _] := io.jwt.decode(bearer_token)
          }

          bearer_token := t if {
              t := cookies["SID-AuthnProxy-Token"]
          }

    - id: auth_proxy
      type: authentication-proxy
      enabled: true
      parameters:
        <<: *slashid_config
        login_page_heading: "Hello!"
        jwt_expected_issuer: https://api.slashid.com
        jwks_url: https://api.slashid.com/.well-known/jwks.json

        login_page_factors:
          - method: "oidc"
            options:
              client_id: "<google client id>"
              provider: "google"
  urls:
    - pattern: "*"
      target: http://youtrack:8000
      plugins:
        auth_proxy:
          enabled: true
        authz_admin_oidc:
          enabled: true
...

Let’s break it down, the authentication proxy configuration specifies oidc as the only valid authentication method. You can read more here on how to configure SlashID to retrieve Google groups as part of the authentication process with OIDC.

Note: you could do the same with AzureAD. Read here to learn more.

The authz_admin_oidc instance of the OPA plugin enforces the check on the presence of Google groups as follows:

  1. Parse the cookies in the headers
  2. Extract the bearer token from the SID-AuthnProxy-Token header
  3. Check if the oidc_groups array in the token contains the developers@example.com group

We could, of course, further restrict the policy to, for instance, specific IP addresses or user agents. The Gate OPA plugin provides a rich input object to the policy with significant information on the incoming request.

Seeing it in action


Conclusion

In this post, we’ve shown how we can easily add Passkeys and fine-grained authorization policies to an arbitrary web application in less than 10 minutes without modifying its source code.

We’d love to hear any feedback you may have! Try out Gate with a free account. If you’d like to use the PII detection plugin, please contact us at contact@slashid.dev.

Vincenzo Iozzo

Vincenzo Iozzo

Share

Twitter Linkedin Facebook

Related articles

Firewalling OpenAI APIs: Data loss prevention and identity access control
Tutorial/14 Sep, 2023

Firewalling OpenAI APIs: Data loss prevention and identity access control

Large Language Models (LLMs) have taken the world by storm, and they are now used for many tasks by consumers and enterprises alike. However, the risk of accidentally disclosing sensitive data to the models is very high as the recent Samsung case shown.

Vincenzo Iozzo
Vincenzo Iozzo
Protecting Exposed APIs: Avoid Data Leaks with SlashID Gate and OPA
Tutorial/5 Sep, 2023

Protecting Exposed APIs: Avoid Data Leaks with SlashID Gate and OPA

Adequately protecting APIs is key to avoid data leaks and breaches.

Vincenzo Iozzo
Vincenzo Iozzo
Using Google Tink to sign JWTs with ECDSA
Tutorial/20 Feb, 2023

Using Google Tink to sign JWTs with ECDSA

In this blog post, we will show how the Tink cryptography library can be used to create, sign, and verify JSON Web Tokens (JWTs), as well as to manage the cryptographic keys for doing so.

Joseph Gardner
Joseph Gardner
SlashID/Identity at scale
Offload complexity •••••••••••••

Onboard users

Move authentication to the edge.

Get started

© 2023 SlashID® Inc.

All Rights Reserved.

Terms · Privacy · System Status

Products

Gate Access Data Vault

SlashID

Blog Careers Talk to us

Developers

Get started Documentation System Status Security

Gallery

E-commerce Multi-tenancy

Social

Twitter Linkedin

We use cookies to improve your experience. Read our cookie policy.