Skip to content

Commit 17c7607

Browse files
Aishwarya Subramanianaishbuilds
authored andcommitted
Filter attributes in SQL logs
SQL queries are logged when :debug option is used. Previously, filter attributes were not masked in the logs. For e.g. select "foos".* from foos where "foos"."passw" = ? LIMIT ? [["passw", "hello"] `password` being one of the filter attributes is written to disk. With this change, filter attributes will be masked as [FILTERED] in the logs. select "foos".* from foos where "foos"."passw" = ? "foos"."passw" = ? LIMIT ? [["passw", "[FILTERED]"]
1 parent 074c7f5 commit 17c7607

File tree

3 files changed

+66
-1
lines changed

3 files changed

+66
-1
lines changed

activerecord/CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
* Filter attributes in SQL logs
2+
3+
Previously, SQL queries in logs containing `ActiveRecord::Base.filter_attributes` were not filtered.
4+
5+
Now, the filter attributes will be masked `[FILTERED]` in the logs when `prepared_statement` is enabled.
6+
7+
```
8+
# Before:
9+
Foo Load (0.2ms) SELECT "foos".* FROM "foos" WHERE "foos"."passw" = ? LIMIT ? [["passw", "hello"], ["LIMIT", 1]]
10+
11+
# After:
12+
Foo Load (0.5ms) SELECT "foos".* FROM "foos" WHERE "foos"."passw" = ? LIMIT ? [["passw", "[FILTERED]"], ["LIMIT", 1]]
13+
```
14+
15+
*Aishwarya Subramanian*
16+
117
* Add database config option `database_tasks`
218
319
If you would like to connect to an external database without any database

activerecord/lib/active_record/log_subscriber.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ def sql(event)
5151

5252
binds = []
5353
payload[:binds].each_with_index do |attr, i|
54-
binds << render_bind(attr, casted_params[i])
54+
attribute_name = attr.respond_to?(:name) ? attr.name : attr[i].name
55+
filtered_params = filter(attribute_name, casted_params[i])
56+
57+
binds << render_bind(attr, filtered_params)
5558
end
5659
binds = binds.inspect
5760
binds.prepend(" ")
@@ -135,6 +138,10 @@ def log_query_source
135138
def extract_query_source_location(locations)
136139
backtrace_cleaner.clean(locations.lazy).first
137140
end
141+
142+
def filter(name, value)
143+
ActiveRecord::Base.inspection_filter.filter_param(name, value)
144+
end
138145
end
139146
end
140147

activerecord/test/cases/bind_parameter_test.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,16 @@ def test_nested_unprepared_statements
189189
assert_predicate @connection, :prepared_statements?
190190
end
191191

192+
def test_binds_with_filtered_attributes
193+
ActiveRecord::Base.filter_attributes = [:auth]
194+
195+
binds = [Relation::QueryAttribute.new("auth_token", "abcd", Type::String.new)]
196+
197+
assert_filtered_log_binds(binds)
198+
199+
ActiveRecord::Base.filter_attributes = []
200+
end
201+
192202
private
193203
def assert_bind_params_to_sql
194204
table = Author.quoted_table_name
@@ -277,6 +287,38 @@ def debug(str)
277287
logger.sql(event)
278288
assert_match %r(\[\["id", 10\]\]\z), logger.debugs.first
279289
end
290+
291+
def assert_filtered_log_binds(binds)
292+
payload = {
293+
name: "SQL",
294+
sql: "select * from users where auth_token = ?",
295+
binds: binds,
296+
type_casted_binds: @connection.send(:type_casted_binds, binds)
297+
}
298+
299+
event = ActiveSupport::Notifications::Event.new(
300+
"foo",
301+
Time.now,
302+
Time.now,
303+
123,
304+
payload)
305+
306+
logger = Class.new(ActiveRecord::LogSubscriber) {
307+
attr_reader :debugs
308+
309+
def initialize
310+
super
311+
@debugs = []
312+
end
313+
314+
def debug(str)
315+
@debugs << str
316+
end
317+
}.new
318+
319+
logger.sql(event)
320+
assert_match %r([[auth_token, [FILTERED]]]), logger.debugs.first
321+
end
280322
end
281323
end
282324
end

0 commit comments

Comments
 (0)