Skip to content

Commit dda4b82

Browse files
authored
Merge pull request #754 from DuendeSoftware/wca/url-too-long-troubleshooting
Added section on max URL or query string length
2 parents 7e1f5af + 702b84d commit dda4b82

File tree

1 file changed

+109
-23
lines changed

1 file changed

+109
-23
lines changed

src/content/docs/identityserver/troubleshooting.md renamed to src/content/docs/identityserver/troubleshooting.mdx

Lines changed: 109 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ redirect_from:
1111
- /identityserver/v7/troubleshooting/wilson/
1212
---
1313

14+
import { Code } from "astro/components";
15+
import { Tabs, TabItem } from "@astrojs/starlight/components";
16+
1417
When troubleshooting an IdentityServer setup we have some tips and tricks to share. These are both ways to get more
1518
information out of the system and how to detect and fix some common problems.
1619

@@ -20,15 +23,15 @@ Duende IdentityServer is a security product and by design the error messages ret
2023
are very short. The actual error message is always written to the logs. The very first step in any troubleshooting
2124
should be to review the IdentityServer logs.
2225

23-
Another common issue is that the logs are redacted and that the interesting/relevant information is overwritten with
24-
**'\[PII is hidden]'**. (For example *The '[PII is hidden]' for signing cannot be smaller than '[PII is hidden]' bits*).
26+
Another common issue is that the logs are redacted and that the interesting/relevant information is overwritten with
27+
**'\[PII is hidden]'**. (For example _The '[PII is hidden]' for signing cannot be smaller than '[PII is hidden]' bits_).
2528
This is a privacy feature of the Microsoft.IdentityModel libraries that we use for token handling. The definition of
2629
possible PII in those libraries is very generous and includes key sizes, URLs etc.
2730

2831
There is a static property that can be set to disable the redacting.
2932

3033
```csharp
31-
IdentityModelEventSource.ShowPII = true;
34+
IdentityModelEventSource.ShowPII = true;
3235
```
3336

3437
We recommend to always set this flag to true in any development and test environment that does not contain real personal
@@ -39,9 +42,9 @@ data.
3942
ASP.NET Core Data Protection is an encryption mechanism that is heavily used by Duende.IdentityServer and the ASP.NET
4043
Core Authentication libraries. If it is not correctly configured it might result in issues such as
4144

42-
* Unable to unprotect the message.State.
43-
* The key `{xxxxx-xxxx-xxx-xxx-xxxxxxx}` was not found in the key ring.
44-
* Failed to unprotect AuthenticationTicket payload for key {key}
45+
- Unable to unprotect the message.State.
46+
- The key `{xxxxx-xxxx-xxx-xxx-xxxxxxx}` was not found in the key ring.
47+
- Failed to unprotect AuthenticationTicket payload for key `{key}`
4548

4649
See [our data protection guide](/identityserver/deployment#data-protection-keys) for more
4750
information.
@@ -126,18 +129,18 @@ found 'Boolean Microsoft.IdentityModel.Tokens.TokenUtilities.IsRecoverableConfig
126129

127130
Errors that we have seen because of IdentityModel version mismatches include:
128131

129-
* IDX10500: Signature validation failed. No security keys were provided to validate the signature.
130-
* System.MissingMethodException: Method not found 'Boolean
132+
- IDX10500: Signature validation failed. No security keys were provided to validate the signature.
133+
- System.MissingMethodException: Method not found 'Boolean
131134
Microsoft.IdentityModel.Tokens.TokenUtilities.IsRecoverableConfiguration(...)'
132-
* Microsoft.AspNetCore.Authentication.AuthenticationFailureException: An error was encountered while handling the remote
135+
- Microsoft.AspNetCore.Authentication.AuthenticationFailureException: An error was encountered while handling the remote
133136
login. ---> System.InvalidOperationException: An invalid request URI was provided. Either the request URI must be an
134137
absolute URI or BaseAddress must be set.
135138

136139
### Diagnosing
137140

138-
Run this command in powershell:
141+
Run this command in PowerShell:
139142

140-
```bash
143+
```powershell
141144
dotnet list package --include-transitive | sls "Microsoft.IdentityModel|System.IdentityModel"
142145
```
143146

@@ -153,7 +156,7 @@ The output should look something like this:
153156
> System.IdentityModel.Tokens.Jwt 7.0.3
154157
```
155158

156-
In the above example it is clear that there are different versions active.
159+
In the example above, it is clear that there are different versions active.
157160

158161
### Fixing
159162

@@ -173,7 +176,7 @@ version used.
173176
In some installations, upgrading .NET and IdentityServer has caused performance issues. Since the IdentityServer and
174177
.NET version upgrades typically are done at the same time, it is sometimes hard to tell what the root cause is
175178
for the performance degradation. When working with installations to find the root cause, there are some dependencies
176-
that have been found to cause issues in specific verisons.
179+
that have been found to cause issues in specific versions.
177180

178181
### PostgreSQL Pooling
179182

@@ -204,13 +207,13 @@ and possible mitigations.
204207

205208
The `Azure.Core` package versions `1.41.0` and prior had an issue that caused delays when accessing Azure resources.
206209
This could be Azure blob storage or key vault for data protection or Azure SQL Server for stores, especially if managed
207-
identities are used. This package is typically not referenced directly but brought in as a transient dependency
210+
identities are used. This package is typically not referenced directly but brought in as a transient dependency
208211
through other packages. Ensure to use version `1.42.0` or later if you are hosting on Azure.
209212

210213
### Entity Framework Core, Microsoft.Data.SqlClient, and SqlServerRetryingExecutionStrategy
211214

212215
As more developers migrate their database-powered application to the cloud,
213-
they will need to handle intermittent connection failures. In most cases, these transient connection failures occur and resolve in a short period of time, allowing the application to self-correct and continue processing requests. The strategy is known as **connection resiliency**.
216+
they will need to handle intermittent connection failures. In most cases, these transient connection failures occur and resolve in a short period of time, allowing the application to self-correct and continue processing requests. The strategy is known as **connection resiliency**.
214217

215218
In recent versions of Entity Framework Core and `Microsoft.Data.SqlClient`, you can enable this retry strategy explicitly, but in the case of `Microsoft.Data.SqlClient`, when operating in a cloud environment, this strategy is enabled by default or defined in the connection string.
216219

@@ -229,8 +232,8 @@ In most cases, this is a _good feature to have enabled_ but there are drawbacks
229232
- Enabling retry on failure causes Entity Framework Core to buffer the result set. This significantly increases memory requirements and causes garbage collection pauses.
230233
- Some versions of `Microsoft.Data.SqlClient` call `Thread.Sleep` that can lock threads for up to **_10 seconds_**. This can lead to thread exhaustion and server unresponsiveness. We've isolated this issue to versions.
231234

232-
| Microsoft.EntityFrameworkCore.SqlServer | Microsoft.Data.SqlClient | Status |
233-
|:----------------------------------------|:-------------------------|:-----------|
235+
| Microsoft.EntityFrameworkCore.SqlServer | Microsoft.Data.SqlClient | Status |
236+
| :-------------------------------------- | :----------------------- | :---------- |
234237
| `8.0.0` | `>=5.1.1` | ✅ Good |
235238
| `8.0.3` | `>=5.1.5` | ❌ Affected |
236239
| `8.0.4` | `>=5.1.5` | ❌ Affected |
@@ -269,6 +272,86 @@ When dealing with external authentication, you may want to set `MapInboundClaims
269272

270273
When dealing with external authentication, you may want to implement `OnTicketReceived` to reduce the size of the cookie. This is a callback that is invoked after the external authentication process is complete. You can use this callback to remove any claims that are not needed by your solution.
271274

275+
## URL and Query String Size Limits and Management
276+
277+
While most browsers currently support URLs longer than 2000 characters, web servers may still return an error status code
278+
when they find that the URL or query string is too long.
279+
280+
For most authentication flows, URLs will stay well under 2000 characters in length. When federating to an external
281+
identity provider, however, URLs can quickly grow too large because of all the query parameters that were added.
282+
283+
Web servers can respond differently when a URL or query string is too large:
284+
285+
- Apache responds with `414 Request-URI Too Large` when a URL exceeds 8190 bytes.
286+
- IIS responds with `404 Not Found` and uses two different substatus codes depending on the issue:
287+
- If the URL exceeds 4096 bytes, the substatus code is `404.14 URL Too Long`.
288+
- If the query string exceeds 2048 bytes, the substatus code is `404.15 Query String Too Long`.
289+
- Nginx responds with `414 Request-URI Too Large` when a URL exceeds 8192 bytes.
290+
291+
To fix this issue, there are two solutions:
292+
293+
### Reduce State Query Parameter Size
294+
295+
When IdentityServer redirects the user to an external Identity Provider, it includes a data protected `state` query parameter.
296+
The combination of this `state` parameter with other data being added by the external IdP can cause the URL to become too large.
297+
You can drastically reduce the size of the `state` parameter by storing the state in IdentityServer, rather than passing it along
298+
in the request URL.
299+
300+
See [External Providers - State, URL length, And ISecureDataFormat](/identityserver/ui/login/external/#state-url-length-and-isecuredataformat)
301+
for more information about this workaround.
302+
303+
### Increase the Maximum Size of URL or Query String data
304+
305+
Depending on the web server you're using, you can change the maximum size of the URL or query string.
306+
307+
:::caution
308+
While increasing the size limits may work for your use case, the first solution is a more robust way to reduce the size
309+
of the query string when federating with an external identity provider.
310+
:::
311+
312+
{/* prettier-ignore */}
313+
<Tabs>
314+
<TabItem label="Apache">
315+
You can increase the value for `LimitRequestLine` to allow longer URLs, by adding or changing this directive in your
316+
server config file (for all virtual hosts), or for specific virtual hosts in their respective `<VirtualHost></VirtualHost>` entry.
317+
318+
See https://httpd.apache.org/docs/2.4/mod/core.html#limitrequestline for more information.
319+
320+
</TabItem>
321+
<TabItem label="Microsoft IIS">
322+
Configure the `requestLimits` XML element to increase the max URL and query string size in your `web.config` file:
323+
<Code
324+
lang="xml"
325+
title="web.config"
326+
code={`
327+
<configuration>
328+
<system.webServer>
329+
<security>
330+
<requestFiltering>
331+
<requestLimits maxUrl="8192" maxQueryString="4096" />
332+
</requestFiltering>
333+
</security>
334+
</system.webServer>
335+
</configuration>
336+
`}
337+
/>
338+
See https://learn.microsoft.com/en-us/iis/configuration/system.webserver/security/requestfiltering/requestlimits/ for more information.
339+
</TabItem>
340+
<TabItem label="Nginx">
341+
You can increase the size for each buffer in `large_client_header_buffers` to allow longer URLs, by adding or changing this directive in the
342+
`http { }` context (for all virtual servers), or for specific virtual servers in their respective `server { }` entry.
343+
344+
This setting has two parameters:
345+
- the number of buffers
346+
- the size of each buffer
347+
348+
The second parameter, the size of the each buffer, determines the maximum URL length.
349+
350+
See https://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers for more information.
351+
352+
</TabItem>
353+
</Tabs>
354+
272355
## X.509 Certificates
273356

274357
When your IdentityServer is hosted in a Windows environment, it is possible that private key material
@@ -298,31 +381,34 @@ System.Security.Cryptography.CryptographicException: Access denied.
298381
```
299382

300383
To fix this issue on Azure hosted web applications, add the following environment variable to the App Service:
384+
301385
```text
302386
WEBSITE_LOAD_USER_PROFILE=1
303387
```
304388

305389
After saving this environment variable, your App Service will restart and Kudu (the engine behind git deployments in Azure App Service)
306390
will load the user profile when running your web application.
307-
For more information about this and other Kudu configuration options, see https://github.com/projectkudu/kudu/wiki/Configurable-settings.
391+
For more information about this and other Kudu configuration options, see https://github.com/projectkudu/kudu/wiki/Configurable-settings.
308392

309393
If you're hosting the web application using IIS on Windows, you'll need to configure the application pool to load the user profile. See https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/advanced?view=aspnetcore-9.0#data-protection
310394
for more information on how to configure the application pool.
311395

312396
### Why does a web application need to load a user profile to work with X.509 certificates?
313397

314398
The `X509Certificate2` class in .NET stores the private key part of a certificate somewhere else depending on the use of `X509KeyStorageFlags`:
315-
* `X509KeyStorageFlags.MachineKeySet` stores the private key in a `Keys` registry subfolder of the certificate store.
316-
* `X509KeyStorageFlags.UserKeySet` stores the private key in the current user's roaming profile folder, e.g. `%AppData%\Microsoft\SystemCertificates\My\Keys`.
399+
400+
- `X509KeyStorageFlags.MachineKeySet` stores the private key in a `Keys` registry subfolder of the certificate store.
401+
- `X509KeyStorageFlags.UserKeySet` stores the private key in the current user's roaming profile folder, e.g. `%AppData%\Microsoft\SystemCertificates\My\Keys`.
317402

318403
When loading a certificate containing both a public and private key in .NET, the private key may also end up in different locations:
319-
* Machine keys end up in the `%ProgramData%\Microsoft\Crypto\RSA\MachineKeys` folder.
320-
* User keys are stored in the current user's roaming profile folder but this time in a different location: `%AppData%\Microsoft\Crypto\RSA`
404+
405+
- Machine keys end up in the `%ProgramData%\Microsoft\Crypto\RSA\MachineKeys` folder.
406+
- User keys are stored in the current user's roaming profile folder but this time in a different location: `%AppData%\Microsoft\Crypto\RSA`
321407

322408
If you don't explicitly use the `X509KeyStorageFlags.MachineKeySet` flag value, the default behavior is to use `X509KeyStorageFlags.DefaultKeySet`.
323409
According to the [.NET documentation][1], this means: _The default key set is used. **The user key set is usually the default**_.
324410

325411
When an application runs without an active user profile, any private key material stored in a user profile can't be accessed.
326412
Even loading a certificate can fail, since the load operation could attempt to store the private key material in the user profile.
327413

328-
[1]: https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509keystorageflags
414+
[1]: https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509keystorageflags

0 commit comments

Comments
 (0)