You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -46,9 +46,10 @@ it by email to the maintainer: sixto.martin.garcia+security@gmail.com
46
46
and from a trusted source. Ruby SAML does not perform any validation that the URL
47
47
you entered is correct and/or safe.
48
48
-**False-Positive Security Warnings:** Some tools may incorrectly report Ruby SAML as a
49
-
potential security vulnerability, due to it's dependency on Nokogiri. Such warnings can
49
+
potential security vulnerability, due to its dependency on Nokogiri. Such warnings can
50
50
be ignored; Ruby SAML uses Nokogiri in a safe way, by always disabling its DTDLOAD option
51
51
and enabling its NONET option.
52
+
-**Prevent Replay attacks:** A replay attack is when an attacker intercepts a valid SAML assertion and "replays" it at a later time to gain unauthorized access. The `ruby-saml` library provides the tools to prevent this, but **you, the developer, must implement the core logic**, see an specific section later in the README.
52
53
53
54
### Supported Ruby Versions
54
55
@@ -179,7 +180,7 @@ def saml_settings
179
180
end
180
181
```
181
182
182
-
The use of settings.issuer is deprecated in favour of settings.sp_entity_id since version 1.11.0
183
+
The use of settings.issuer is deprecated in favor of settings.sp_entity_id since version 1.11.0
183
184
184
185
Some assertion validations can be skipped by passing parameters to `RubySaml::Response.new()`.
185
186
For example, you can skip the `AuthnStatement`, `Conditions`, `Recipient`, or the `SubjectConfirmation`
@@ -255,13 +256,13 @@ Ruby SAML allows different ways to validate the signature of the SAML Response:
255
256
`idp_cert_fingerprint` and `idp_cert_fingerprint_algorithm` parameters.
256
257
257
258
In addition, you may pass the option `:relax_signature_validation` to `SloLogoutrequest` and
258
-
`Logoutresponse` if want to skip signature validation on logout.
259
+
`Logoutresponse` if you want to skip signature validation on logout.
259
260
260
261
The `idp_cert_fingerprint` option is deprecated for the following reasons. It will be
261
262
removed in Ruby SAML version 2.1.0.
262
263
1. It only works with HTTP-POST binding, not HTTP-Redirect, since the full certificate
263
264
is not sent in the Redirect URL parameters.
264
-
2. It is theoretically be susceptible to collision attacks, by which a malicious
265
+
2. It is theoretically susceptible to collision attacks, by which a malicious
265
266
actor could impersonate the IdP. (However, as of January 2025, such attacks have not
266
267
been publicly demonstrated for SHA-256.)
267
268
3. It has been removed already from several other SAML libraries in other languages.
@@ -365,8 +366,7 @@ Those return an Hash instead of a `Settings` object, which may be useful for con
365
366
366
367
### Validating Signature of Metadata and retrieve settings
367
368
368
-
Right now there is no method at ruby_saml to validate the signature of the metadata that gonna be parsed,
369
-
but it can be done as follows:
369
+
Right now there is no method at ruby_saml to validate the signature of the metadata that is going to be parsed, but it can be done as follows:
370
370
* Download the XML.
371
371
* Validate the Signature, providing the cert.
372
372
* Provide the XML to the parse method if the signature was validated
You may require the IdP to sign its SAML Assertions using the following setting.
658
-
With will add `<md:SPSSODescriptor WantAssertionsSigned="true">` to your SP Metadata XML.
658
+
This will add `<md:SPSSODescriptor WantAssertionsSigned="true">` to your SP Metadata XML.
659
659
The signature will be checked against the `<md:KeyDescriptor use="signing">` element
660
660
present in the IdP's metadata.
661
661
@@ -687,7 +687,7 @@ advanced usage scenarios:
687
687
- Specifying separate SP certificates for signing and encryption.
688
688
689
689
The `sp_cert_multi` parameter replaces `certificate` and `private_key`
690
-
(you may not specify both pparameters at the same time.) `sp_cert_multi` has the following shape:
690
+
(you may not specify both parameters at the same time.) `sp_cert_multi` has the following shape:
691
691
692
692
```ruby
693
693
settings.sp_cert_multi = {
@@ -729,7 +729,7 @@ JRuby cannot support ECDSA due to a [known issue](https://github.com/jruby/jruby
729
729
### Audience Validation
730
730
731
731
A service provider should only consider a SAML response valid if the IdP includes an <AudienceRestriction>
732
-
element containting an <Audience> element that uniquely identifies the service provider. Unless you specify
732
+
element containing an <Audience> element that uniquely identifies the service provider. Unless you specify
733
733
the `skip_audience` option, Ruby SAML will validate that each SAML response includes an <Audience> element
734
734
whose contents matches `settings.sp_entity_id`.
735
735
@@ -762,7 +762,7 @@ def sp_logout_request
762
762
settings = saml_settings
763
763
764
764
if settings.idp_slo_service_url.nil?
765
-
logger.info "SLO IdP Endpoint not found in settings, executing then a normal logout'"
765
+
logger.info "SLO IdP Endpoint not found in settings, then executing a normal logout'"
766
766
delete_session
767
767
else
768
768
@@ -910,7 +910,7 @@ end
910
910
911
911
### Attribute Service
912
912
913
-
To request attributes from the IdP the SP needs to provide an attribute service within it's metadata and reference the index in the assertion.
913
+
To request attributes from the IdP the SP needs to provide an attribute service within its metadata and reference the index in the assertion.
914
914
915
915
```ruby
916
916
settings =RubySaml::Settings.new
@@ -936,7 +936,7 @@ or underscore, and can only contain letters, digits, underscores, hyphens, and p
936
936
937
937
### Custom Metadata Fields
938
938
939
-
Some IdPs may require to add SPs to add additional fields (Organization, ContactPerson, etc.)
939
+
Some IdPs may require SPs to add additional fields (Organization, ContactPerson, etc.)
940
940
into the SP metadata. This can be done by extending the `RubySaml::Metadata` class and
941
941
overriding the `#add_extras` method where the first arg is a
942
942
[Nokogiri::XML::Builder](https://nokogiri.org/rdoc/Nokogiri/XML/Builder.html) object as per
@@ -964,6 +964,111 @@ end
964
964
MyMetadata.new.generate(settings)
965
965
```
966
966
967
+
### Preventing Replay Attacks
968
+
969
+
A replay attack is when an attacker intercepts a valid SAML assertion and "replays" it at a later time to gain unauthorized access.
970
+
971
+
The library only checks the assertion's validity window (`NotBefore` and `NotOnOrAfter` conditions). An attacker can replay a valid assertion as many times as they want within this window.
972
+
973
+
A robust defense requires tracking of assertion IDs to ensure any given assertion is only accepted once.
974
+
975
+
#### 1. Extract the Assertion ID after Validation
976
+
977
+
After a response has been successfully validated, get the assertion ID. The library makes this available via `response.assertion_id`.
978
+
979
+
980
+
#### 2. Store the ID with an Expiry
981
+
982
+
You must store this ID in a persistent cache (like Redis or Memcached) that is shared across your servers. Do not store it in the user's session, as that is not a secure cache.
983
+
984
+
The ID should be stored until the assertion's validity window has passed. You will need to check how long the trusted IdPs consider the assertion valid and then add the allowed_clock_drift.
985
+
986
+
You can define a global value, or set this value dinamically based on the `not_on_or_after` value of the re + `allowed_clock_drift`.
987
+
988
+
```ruby
989
+
# In your `consume` action, after a successful validation:
990
+
if response.is_valid?
991
+
# Prevent replay of this specific assertion
992
+
assertion_id = response.assertion_id
993
+
authorize_failure("Assertion ID is mandatory") if assertion_id.nil?
### Enforce SP-Initiated Flow with `InResponseTo` validation
1031
+
1032
+
This is the best way to prevent IdP-initiated logins and ensure that you only accept assertions that you recently requested.
1033
+
1034
+
#### 1. Store the `AuthnRequest` ID
1035
+
1036
+
When you create an `AuthnRequest`, the library assigns it a unique ID. You must store this ID, for example in the user's session *before* redirecting them to the IdP.
1037
+
1038
+
```ruby
1039
+
definit
1040
+
request =OneLogin::RubySaml::Authrequest.new
1041
+
# The unique ID of the request is in request.uuid
1042
+
session[:saml_request_id] = request.uuid
1043
+
redirect_to(request.create(saml_settings))
1044
+
end
1045
+
```
1046
+
1047
+
#### 2. Validate the `InResponseTo` value of the `Response` with the Stored ID
1048
+
1049
+
When you process the `SAMLResponse`, retrieve the ID from the session and pass it to the `Response` constructor. Use `session.delete` to ensure the ID can only be used once.
1050
+
1051
+
```ruby
1052
+
defconsume
1053
+
request_id = session.delete(:saml_request_id) # Use delete to prevent re-use
1054
+
1055
+
# You can reject the response if no previous saml_request_id was stored
1056
+
raise"IdP-initiaited detected"if request_id.nil?
1057
+
1058
+
response =OneLogin::RubySaml::Response.new(
1059
+
params[:SAMLResponse],
1060
+
settings: saml_settings,
1061
+
matches_request_id: request_id
1062
+
)
1063
+
1064
+
if response.is_valid?
1065
+
# ... authorize user
1066
+
else
1067
+
# Response is invalid, errors in response.errors
1068
+
end
1069
+
end
1070
+
```
1071
+
967
1072
## Contributing
968
1073
969
1074
### Pay it Forward: Support RubySAML and Strengthen Open-Source Security
RubySaml `1.x` used a combination of REXML and Nokogiri for XML parsing and generation.
77
85
In `2.0.0`, REXML has been replaced with Nokogiri. As a result, there are minor differences
78
-
in how XML is generated, ncluding SAML requests and SP Metadata:
86
+
in how XML is generated, including SAML requests and SP Metadata:
79
87
80
88
1. All XML namespace declarations will be on the root node of the XML. Previously,
81
89
some declarations such as `xmlns:ds` were done on child nodes.
@@ -121,7 +129,7 @@ The reasons for this change are:
121
129
### Removal of embed_sign setting
122
130
123
131
The deprecated `settings.security[:embed_sign]` parameter has been removed. If you were using it, please instead switch
124
-
to using both the `settings.idp_sso_service_binding` and `settings.idp_slo_service_binding` parameters as show below.
132
+
to using both the `settings.idp_sso_service_binding` and `settings.idp_slo_service_binding` parameters as shown below.
125
133
(This new syntax is supported on version 1.13.0 and later.)
126
134
127
135
```ruby
@@ -230,8 +238,8 @@ how validation happens in the toolkit and also the toolkit by default will check
230
238
when parsing a SAML Message (`settings.check_malformed_doc`).
231
239
232
240
The SignedDocument class defined at xml_security.rb experienced several changes.
233
-
We don't expect compatibilty issues if you use the main methods offered by ruby-saml, but if
234
-
you use a fork or customized usage, is possible that you need to adapt your code.
241
+
We don't expect compatibility issues if you use the main methods offered by ruby-saml, but if
242
+
you use a fork or customized usage, it is possible that you will need to adapt your code.
235
243
236
244
## Upgrading from 1.12.x to 1.13.0
237
245
@@ -257,7 +265,7 @@ in favor of `idp_sso_service_url` and `idp_slo_service_url`. The `IdpMetadataPar
257
265
258
266
## Upgrading from 1.10.x to 1.11.0
259
267
260
-
Version `1.11.0` deprecates the use of `settings.issuer` in favour of `settings.sp_entity_id`.
268
+
Version `1.11.0` deprecates the use of `settings.issuer` in favor of `settings.sp_entity_id`.
261
269
There are two new security settings: `settings.security[:check_idp_cert_expiration]` and
262
270
`settings.security[:check_sp_cert_expiration]` (both false by default) that check if the
263
271
IdP or SP X.509 certificate has expired, respectively.
@@ -268,7 +276,7 @@ Version `1.10.1` improves Ruby 1.8.7 support.
268
276
269
277
## Upgrading from 1.9.0 to 1.10.0
270
278
271
-
Version `1.10.0` improves IdpMetadataParser to allow parse multiple IDPSSODescriptor,
279
+
Version `1.10.0` improves IdpMetadataParser to allow parsing multiple IDPSSODescriptor,
272
280
Add Subject support on AuthNRequest to allow SPs provide info to the IdP about the user
273
281
to be authenticated and updates the format_cert method to accept certs with /\x0d/
274
282
@@ -352,7 +360,7 @@ It adds security improvements in order to prevent Signature wrapping attacks.
352
360
353
361
## Upgrading from 1.1.x to 1.2.x
354
362
355
-
Version `1.2` adds IDP metadata parsing improvements, uuid deprecation in favour of SecureRandom,
363
+
Version `1.2` adds IDP metadata parsing improvements, uuid deprecation in favor of SecureRandom,
356
364
refactor error handling and some minor improvements.
357
365
358
366
There is no compatibility issue detected.
@@ -367,7 +375,7 @@ Version `1.1` adds some improvements on signature validation and solves some nam
367
375
368
376
Version `1.0` is a recommended update for all Ruby SAML users as it includes security fixes.
369
377
370
-
Version `1.0` adds security improvements like entity expansion limitation, more SAML message validations, and other important improvements like decrypt support.
378
+
Version `1.0` adds security improvements like entity expansion limitation, more SAML message validations, and other important improvements like decryption support.
0 commit comments