shrine 3.10.1 → 3.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/doc/release_notes/3.10.2.md +31 -0
- data/lib/shrine/plugins/derivation_endpoint.rb +13 -15
- data/lib/shrine/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2027c3833ffb021cf9fe9be3761c3238ca807eb1591ed910b585b226cad80497
|
|
4
|
+
data.tar.gz: fd9ce3716ac5c110a306f4823acf90de7cf673132ef90b181e8d7040cc8d74d0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9181db3a505b16fba406a6d98cc2f4a37222fcbacdf47427d5ec80d087ef3746b0db2152d21685b89f8cfc77db766b0ed13f1b976241354dc48b9e82aaa1fd35
|
|
7
|
+
data.tar.gz: 4f891d6fcfd5cdd29a39e04479d42d20bc7a6511557a2f82f85dc6889536bf38be9b5f281389fe6751ce7e26271bd1c85897c6e899b6ba3e08d3070ffc1e717e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 3.10.2 (2026-10-11)
|
|
2
|
+
|
|
3
|
+
* `derivation_endpoint` – Prevent bypassing CDN caching by modifying the encoding or structure of the signed URL query string (@Antsiscool, @janko)
|
|
4
|
+
|
|
1
5
|
## 3.10.1 (2026-10-10)
|
|
2
6
|
|
|
3
7
|
* `model` – Make `Attacher#write` a no-op when the attacher isn't backed by a model, fixing `remove_invalid` raising `NoMethodError` on attachers without a record (@janko)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Shrine 3.10.2
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Security
|
|
6
|
+
|
|
7
|
+
* The `derivation_endpoint` plugin now verifies the URL signature against the
|
|
8
|
+
URL exactly as it was received. Previously, query parameters were decoded and
|
|
9
|
+
re-encoded before verification, so the same signed URL could be requested
|
|
10
|
+
through an unlimited number of variants that all passed verification. Since
|
|
11
|
+
each variant is a separate cache key on a CDN, this could be used to bypass
|
|
12
|
+
CDN caching and repeatedly trigger derivations on the server:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
/derivations/thumbnail/...?type=image%2Fwebp&signature=abc123 # original
|
|
16
|
+
/derivations/thumbnail/...?%74ype=image%2Fwebp&signature=abc123 # encoded parameter name
|
|
17
|
+
/derivations/thumbnail/...?&&type=image%2Fwebp&signature=abc123 # empty parameters
|
|
18
|
+
/derivations/thumbnail/...?type=image%2Fwebp&signature=abc123?foo # appended query
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
These variants now return a `403 Forbidden` response. The `signature` query
|
|
22
|
+
parameter is also required to be the last parameter, which is where Shrine
|
|
23
|
+
always puts it.
|
|
24
|
+
|
|
25
|
+
## Backwards compatibility
|
|
26
|
+
|
|
27
|
+
* URLs generated by the `derivation_endpoint` plugin are unchanged, so
|
|
28
|
+
existing URLs remain valid. However, if a proxy between the client and your
|
|
29
|
+
application rewrites the query string (e.g. re-encodes characters, reorders
|
|
30
|
+
parameters, or appends tracking parameters), signature verification will now
|
|
31
|
+
fail for those requests.
|
|
@@ -717,29 +717,27 @@ class Shrine
|
|
|
717
717
|
|
|
718
718
|
# Returns a URL with the `signature` query parameter
|
|
719
719
|
def sign_url(url)
|
|
720
|
-
path, query = url.split("?")
|
|
720
|
+
path, query = url.split("?", 2)
|
|
721
721
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
query = Rack::Utils.build_query(params)
|
|
722
|
+
signature = generate_signature("#{path}?#{query}")
|
|
723
|
+
query = [query, "signature=#{signature}"].reject { |part| part.to_s.empty? }.join("&")
|
|
726
724
|
|
|
727
725
|
"#{path}?#{query}"
|
|
728
726
|
end
|
|
729
727
|
|
|
730
|
-
#
|
|
731
|
-
# value in the `signature` query parameter. Raises
|
|
732
|
-
# the `signature` parameter is missing or its value
|
|
733
|
-
# calculated signature.
|
|
728
|
+
# Calculates the signature from the URL and checks whether it matches the
|
|
729
|
+
# value in the trailing `signature` query parameter. Raises
|
|
730
|
+
# `InvalidSignature` if the `signature` parameter is missing or its value
|
|
731
|
+
# doesn't match the calculated signature. The URL is verified as is,
|
|
732
|
+
# without any normalization, so that each signed URL has only one valid
|
|
733
|
+
# form (otherwise variants of it could be used to bypass CDN caching).
|
|
734
734
|
def verify_url(url)
|
|
735
|
-
path, query = url.split("?")
|
|
736
|
-
|
|
737
|
-
params = Rack::Utils.parse_query(query.to_s)
|
|
738
|
-
signature = params.delete("signature")
|
|
735
|
+
path, query = url.split("?", 2)
|
|
739
736
|
|
|
740
|
-
|
|
737
|
+
params = query.to_s.split("&", -1)
|
|
738
|
+
signature = params.pop.delete_prefix("signature=") if params.last&.start_with?("signature=")
|
|
741
739
|
|
|
742
|
-
verify_signature("#{path}?#{
|
|
740
|
+
verify_signature("#{path}?#{params.join("&")}", signature)
|
|
743
741
|
end
|
|
744
742
|
|
|
745
743
|
def verify_signature(string, signature)
|
data/lib/shrine/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: shrine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.10.
|
|
4
|
+
version: 3.10.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Janko Marohnić
|
|
@@ -491,6 +491,7 @@ files:
|
|
|
491
491
|
- doc/release_notes/3.1.0.md
|
|
492
492
|
- doc/release_notes/3.10.0.md
|
|
493
493
|
- doc/release_notes/3.10.1.md
|
|
494
|
+
- doc/release_notes/3.10.2.md
|
|
494
495
|
- doc/release_notes/3.2.0.md
|
|
495
496
|
- doc/release_notes/3.2.1.md
|
|
496
497
|
- doc/release_notes/3.2.2.md
|