security
URL parameters
login
web development
parameter handling

How do I disable resolving login parameters passed as url parameters / from the url

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Passing login credentials (username, password) as URL query parameters is a serious security vulnerability. URLs are logged in browser history, server access logs, proxy logs, and referrer headers, meaning credentials end up in plaintext in multiple locations. This article explains how to disable URL-based login parameters in common frameworks and enforce secure alternatives.

Why URL Parameters for Login Are Dangerous

 
# DANGEROUS: credentials visible in URL
https://example.com/login?username=admin&password=secret123

This exposes credentials in:

  • Browser history: Anyone with access to the browser can see the URL
  • Server access logs: Apache/Nginx access logs record full URLs by default
  • Proxy and CDN logs: Corporate proxies, load balancers, and CDNs log URLs
  • Referrer headers: If the user navigates to another site after login, the full URL is sent in the Referer header
  • Browser bookmarks: Users may accidentally bookmark the URL with credentials
  • Shoulder surfing: The URL is visible in the address bar

Spring Security (Java)

Spring Security can process login credentials from both URL parameters and POST body. To restrict to POST only:

java
1@Configuration
2@EnableWebSecurity
3public class SecurityConfig {
4
5    @Bean
6    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
7        http
8            .formLogin(form -> form
9                .loginPage("/login")
10                .loginProcessingUrl("/api/login")
11                .usernameParameter("username")
12                .passwordParameter("password")
13            )
14            .authorizeHttpRequests(auth -> auth
15                .requestMatchers("/login", "/public/**").permitAll()
16                .anyRequest().authenticated()
17            );
18        return http.build();
19    }
20}

Spring's UsernamePasswordAuthenticationFilter only processes POST requests by default. To explicitly enforce this and reject GET requests with credentials:

java
1@RestController
2public class LoginController {
3
4    @GetMapping("/api/login")
5    public ResponseEntity<?> rejectGetLogin() {
6        return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED)
7            .body("Login via GET is not allowed. Use POST.");
8    }
9}

Express.js (Node.js)

Middleware to strip credentials from query parameters:

javascript
1const express = require('express');
2const app = express();
3
4// Middleware: reject login attempts via URL parameters
5app.use('/login', (req, res, next) => {
6    if (req.query.username || req.query.password) {
7        return res.status(400).json({
8            error: 'Credentials must not be sent as URL parameters. Use POST body.'
9        });
10    }
11    next();
12});
13
14// Only accept POST for login
15app.post('/login', express.json(), (req, res) => {
16    const { username, password } = req.body;
17    // Authenticate using body parameters only
18});
19
20// Reject GET to /login
21app.get('/login', (req, res) => {
22    res.status(405).json({ error: 'Use POST method for login' });
23});

Django (Python)

Django's LoginView uses POST by default. Add explicit GET rejection:

python
1from django.views.decorators.http import require_POST
2from django.http import JsonResponse
3
4@require_POST
5def login_view(request):
6    # Only POST requests reach here
7    username = request.POST.get('username')
8    password = request.POST.get('password')
9    # ... authenticate

Add middleware to strip credentials from all URLs:

python
1class StripCredentialsMiddleware:
2    def __init__(self, get_response):
3        self.get_response = get_response
4
5    def __call__(self, request):
6        sensitive_params = {'username', 'password', 'token', 'secret', 'api_key'}
7        if request.GET.keys() & sensitive_params:
8            from django.http import HttpResponseBadRequest
9            return HttpResponseBadRequest(
10                'Credentials must not be passed as URL parameters.'
11            )
12        return self.get_response(request)

ASP.NET Core

csharp
1// Middleware to reject credentials in query strings
2app.Use(async (context, next) =>
3{
4    var sensitiveParams = new[] { "username", "password", "token" };
5    var queryKeys = context.Request.Query.Keys;
6
7    if (sensitiveParams.Any(p => queryKeys.Contains(p, StringComparer.OrdinalIgnoreCase)))
8    {
9        context.Response.StatusCode = 400;
10        await context.Response.WriteAsync("Credentials must not be sent as URL parameters.");
11        return;
12    }
13
14    await next();
15});

Nginx / Apache: Strip Parameters at the Web Server Level

Nginx

Redirect requests containing credentials in the URL:

nginx
1server {
2    location /login {
3        # Reject GET requests to login endpoint
4        if ($request_method = GET) {
5            return 405;
6        }
7
8        # Strip sensitive query parameters
9        if ($args ~* "(^|&)(password|token)=") {
10            return 400;
11        }
12
13        proxy_pass http://backend;
14    }
15}

Apache

apache
1RewriteEngine On
2
3# Block requests with password in query string
4RewriteCond %{QUERY_STRING} (^|&)(password|token)= [NC]
5RewriteRule ^/login$ - [F,L]
6
7# Only allow POST to /login
8RewriteCond %{REQUEST_METHOD} !POST
9RewriteRule ^/login$ - [R=405,L]

HTML Form Best Practice

Ensure your login form uses POST:

html
1<!-- CORRECT: credentials sent in request body -->
2<form action="/login" method="POST">
3    <input type="text" name="username" />
4    <input type="password" name="password" />
5    <button type="submit">Login</button>
6</form>
7
8<!-- WRONG: credentials appear in URL -->
9<form action="/login" method="GET">
10    ...
11</form>

Secure Alternatives

MethodSecurity LevelNotes
POST body over HTTPSGoodStandard approach
Authorization header (Basic)GoodBase64 encoded, requires HTTPS
Authorization header (Bearer)BestToken-based, no credentials in transit
OAuth 2.0 / OpenID ConnectBestDelegated authentication
Secure cookiesGoodHttpOnly, Secure, SameSite flags

Common Pitfalls

  • HTTPS does not protect URLs in logs: While HTTPS encrypts the URL in transit, the URL (including query parameters) is still visible in server logs, browser history, and referer headers. HTTPS alone does not make URL credentials safe.
  • Tokens and Cookies: Use secure tokens or cookies for session management. Set HttpOnly, Secure, and SameSite flags on session cookies.
  • API keys in URLs: Some APIs pass keys as query parameters (?api_key=...). This has the same logging exposure. Prefer sending API keys in the Authorization header.
  • Client-side redirects: JavaScript redirects like window.location = '/dashboard?token=...' expose tokens in browser history. Use history.replaceState() to strip the parameter immediately after reading it.
  • Logging middleware: Audit your logging configuration. Many logging frameworks record full request URLs by default. Configure them to redact sensitive parameters.

Summary

  • Never pass login credentials as URL query parameters — they end up in logs, history, and referrer headers
  • Enforce POST-only login endpoints in your framework (Spring Security, Express, Django, ASP.NET)
  • Add middleware to reject requests with sensitive parameters in the URL
  • Use HTTPS with POST body, Authorization headers, or token-based authentication
  • Configure web servers (Nginx/Apache) as an additional defense layer

Course illustration
Course illustration

All Rights Reserved.