Mitigation Strategy: Enforce Uniqueness within friendly_id
Configuration
Description: This strategy leverages friendly_id
's built-in features to manage slug uniqueness, including scopes and conflict resolution.
- Application-Level Validation (using
friendly_id
):- Step 1 (Developer): In your ActiveRecord model, use the
validates
clause in conjunction withfriendly_id
.class YourModel < ApplicationRecord extend FriendlyId friendly_id :name, use: :slugged # Or your configuration validates :slug, presence: true, uniqueness: { scope: :your_scope, case_sensitive: false } end
- Step 2 (Developer): If you have a custom scope, replace
:your_scope
with the actual scope (e.g.,:user_id
,[:category_id, :year]
). If you don't have a scope, remove thescope
option. This is crucial for preventing collisions within the intended scope. - Step 3 (Developer): Ensure
case_sensitive: false
is set unless you specifically need case-sensitive slugs (which is rare and generally discouraged).
- Step 1 (Developer): In your ActiveRecord model, use the
- Handle Uniqueness Failures Gracefully (within
friendly_id
):- Step 1 (Developer): Understand
friendly_id
's default conflict resolution behavior. It typically appends a sequence number or UUID to make the slug unique. Read thefriendly_id
documentation on conflict resolution. - Step 2 (Developer): If you need custom retry logic, override the
should_generate_new_friendly_id?
method in your model. This allows you to control when a new slug is generated.def should_generate_new_friendly_id? name_changed? || super # Regenerate if name changes, or if friendly_id decides it's needed end
- Step 3 (Developer): You can also customize the
normalize_friendly_id
method to control how the slug is generated, including how conflicts are resolved. This is more advanced and rarely needed.
- Step 1 (Developer): Understand
-
Threats Mitigated:
- Slug Uniqueness Violations (within
friendly_id
's scope): (Severity: High) - Prevents data corruption, incorrect record retrieval, and application errors caused by duplicate slugs within the defined scope. - Incorrect Record Retrieval (within scope): (Severity: High) - Ensures that users are directed to the correct record when using a slug, considering the defined scope.
- Slug Uniqueness Violations (within
-
Impact:
- Slug Uniqueness Violations (within scope): Risk significantly reduced (effectiveness depends on correct scope definition).
- Incorrect Record Retrieval (within scope): Risk significantly reduced.
-
Currently Implemented:
- Application-Level Validation: Yes, in
app/models/post.rb
- Handle Uniqueness Failures Gracefully: Partially, relying on
friendly_id
's default behavior.
- Application-Level Validation: Yes, in
-
Missing Implementation:
- Custom retry logic (overriding
should_generate_new_friendly_id?
) is missing. We should evaluate if the default behavior is sufficient.
- Custom retry logic (overriding
Mitigation Strategy: Strengthen Slug Generation with friendly_id
Description: This strategy uses friendly_id
's features to create less predictable slugs, making them harder to guess.
- Use
SecureRandom
(withinslug_candidates
):- Step 1 (Developer): Modify your
slug_candidates
method in your model to include aSecureRandom
component. This is essential if your slug isn't solely based on a user-provided, unpredictable attribute.# app/models/your_model.rb friendly_id :slug_candidates, use: :slugged def slug_candidates [ :name, [:name, SecureRandom.hex(8)], # Append 8 random hex characters [:name, SecureRandom.uuid] # Or, append a UUID ] end
- Step 2 (Developer): Choose an appropriate level of randomness (e.g.,
hex(8)
,uuid
). Longer is generally better for security. This makes the slug less predictable even if thename
is guessable.
- Step 1 (Developer): Modify your
- Avoid Predictable Patterns (in
slug_candidates
):- Step 1 (Developer): Never use sequential IDs or timestamps alone as the sole basis for slugs within the
slug_candidates
array. - Step 2 (Developer): If using timestamps, always combine them with a random component (e.g.,
SecureRandom.hex
) within theslug_candidates
array.
- Step 1 (Developer): Never use sequential IDs or timestamps alone as the sole basis for slugs within the
-
Threats Mitigated:
- Slug Generation Predictability: (Severity: Medium) - Makes it harder for attackers to guess valid slugs.
- Resource Enumeration: (Severity: Medium) - Prevents attackers from systematically trying different slugs to discover all resources.
-
Impact:
- Slug Generation Predictability: Risk significantly reduced.
- Resource Enumeration: Risk significantly reduced.
-
Currently Implemented:
- Using
slug_candidates
with:name
inapp/models/post.rb
. This is partially implemented.
- Using
-
Missing Implementation:
- We are not currently appending a
SecureRandom
component to theslug_candidates
. This is a critical missing piece and should be implemented immediately. We need to modify theslug_candidates
method inapp/models/post.rb
.
- We are not currently appending a
Mitigation Strategy: Utilize friendly_id
's History Module
Description: This strategy uses friendly_id
's :history
module to handle slug changes gracefully and prevent broken links.
- Enable the History Module:
- Step 1 (Developer): Include the
:history
module in yourfriendly_id
configuration.# app/models/your_model.rb friendly_id :name, use: [:slugged, :history]
- Step 2 (Developer): Run the
friendly_id
generator to create the necessary migration:rails generate friendly_id
- Step 3 (Developer): Run the migration:
rails db:migrate
- Step 1 (Developer): Include the
- Understand Redirect Behavior:
- Step 1 (Developer):
friendly_id
will automatically create records in thefriendly_id_slugs
table when a slug changes. - Step 2 (Developer): When you use
YourModel.friendly.find(old_slug)
,friendly_id
will automatically find the correct record, even if the slug has changed. It handles the redirection internally.
- Step 1 (Developer):
-
Threats Mitigated:
- Broken Links After Slug Changes: (Severity: Medium) - Prevents broken links if a slug is updated.
- SEO Issues After Slug Changes: (Severity: Medium) - Maintains SEO by allowing search engines to find the content even after a slug change.
-
Impact:
- Broken Links: Risk significantly reduced.
- SEO Issues: Risk significantly reduced.
-
Currently Implemented:
- We are using the
:history
module inapp/models/post.rb
. The migration has been run.
- We are using the
-
Missing Implementation:
- None. This strategy is fully implemented.
Mitigation Strategy: Customize Slug Generation with normalize_friendly_id
(Advanced)
Description: This strategy involves overriding the normalize_friendly_id
method to have fine-grained control over how slugs are generated, including sanitization and conflict resolution. This is generally not needed if you're using slug_candidates
and basic sanitization appropriately.
- Override
normalize_friendly_id
:- Step 1 (Developer): Define the
normalize_friendly_id
method in your model.# app/models/your_model.rb def normalize_friendly_id(input) # Custom sanitization and normalization logic here # Example: input.to_s.downcase.gsub(/[^a-z0-9\-_]+/, '-') end
- Step 2 (Developer): Implement your custom logic. This could include:
- More aggressive sanitization.
- Custom character replacements.
- Alternative conflict resolution strategies (though
slug_candidates
is usually preferred).
- Step 1 (Developer): Define the
- Thorough Testing:
- Step 1 (Developer): Test extensively to ensure your custom logic works as expected and doesn't introduce any regressions.
-
Threats Mitigated:
- Slug Manipulation/Injection (Fine-grained Control): (Severity: High) - Allows for very specific sanitization rules.
- Slug Uniqueness Violations (Custom Conflict Resolution): (Severity: High) - Provides an alternative way to handle conflicts (but
slug_candidates
is generally better).
-
Impact:
- Slug Manipulation/Injection: Risk can be further reduced (but proper sanitization before calling
friendly_id
is still crucial). - Slug Uniqueness Violations: Risk can be managed differently (but
slug_candidates
and database constraints are the primary defenses).
- Slug Manipulation/Injection: Risk can be further reduced (but proper sanitization before calling
-
Currently Implemented:
- Not implemented. We are relying on
friendly_id
's default normalization.
- Not implemented. We are relying on
-
Missing Implementation:
- Not currently needed, as we should focus on proper sanitization before passing data to
friendly_id
. This is an advanced technique to be used only if absolutely necessary.
- Not currently needed, as we should focus on proper sanitization before passing data to