Verified Commit f6c4a2f7 authored by paz's avatar paz

Strip HTML-part if keywords are present to stop leaking them.

The HTML-part of multipart/alternative-messages also contain the
keywords. We don't parse them because we don't touch any HTML. In order
to prevent the keywords from being disclosed to third parties (e.g.
through resent messages), we strip the HTML-part completely.
parent da2371b0
Pipeline #22344 passed with stages
in 13 minutes and 28 seconds
......@@ -3,6 +3,13 @@ Change Log
This project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
### Fixed
* Stop leaking keywords to third parties by stripping HTML from multipart/alternative messages if they contain keywords. (#399)
## [3.3.0] / 2018-09-04
### Fixed
......
module Schleuder
module Filters
def self.strip_html_from_alternative_if_keywords_present(list, mail)
if mail[:content_type].blank? ||
mail[:content_type].content_type != 'multipart/alternative' ||
mail.keywords.blank?
return false
end
Schleuder.logger.debug 'Stripping html-part from multipart/alternative-message because it contains keywords'
mail.parts.delete_if do |part|
part[:content_type].content_type == 'text/html'
end
mail.content_type = 'multipart/mixed'
mail.add_pseudoheader(:note, I18n.t('pseudoheaders.stripped_html_from_multialt_with_keywords'))
end
end
end
......@@ -251,6 +251,7 @@ de:
invalid_input: "Ungültige Angabe. Gültig sind: URLs, OpenPGP-Fingerabdrücke, oder Emailadressen."
pseudoheaders:
stripped_html_from_multialt: Diese Email enthielt einen alternativen HTML-Teil, der PGP-Daten beinhaltete. Der HTML-Teil wurde entfernt, um die Email sauberer analysieren zu können.
stripped_html_from_multialt_with_keywords: Diese Email enthielt Schlüsselwörter und einen alternativen HTML-Teil. Der HTML-Teil wurde entfernt, um zu verhindern dass diese Schlüsselwörter Aussenstehenden bekannt werden.
signature_states:
unknown: "Unbekannte Signatur von unbekanntem Schlüssel 0x%{fingerprint}"
unsigned: "Unsigniert"
......
......@@ -255,6 +255,7 @@ en:
invalid_input: "Invalid input. Allowed are: URLs, OpenPGP-fingerprints, or email-addresses."
pseudoheaders:
stripped_html_from_multialt: This message included an alternating HTML-part that contained PGP-data. The HTML-part was removed to enable parsing the message more properly.
stripped_html_from_multialt_with_keywords: This message included keywords and an alternating HTML-part. The HTML-part was removed to prevent the disclosure of these keywords to third parties.
signature_states:
unknown: "Unknown signature by unknown key 0x%{fingerprint}"
unsigned: "Unsigned"
......
......@@ -79,6 +79,7 @@ describe Schleuder::Filters::Runner do
'receive_signed_only',
'receive_encrypted_only',
'receive_from_subscribed_emailaddresses_only',
'strip_html_from_alternative_if_keywords_present'
]
end
it 'loads custom filters from filters_dir and sorts them in, ignores filter not following convention' do
......@@ -101,6 +102,7 @@ describe Schleuder::Filters::Runner do
'receive_encrypted_only',
'post_example',
'receive_from_subscribed_emailaddresses_only',
'strip_html_from_alternative_if_keywords_present'
]
end
it 'loads custom filters from filters_dir and sorts them in with missing dir' do
......@@ -122,6 +124,7 @@ describe Schleuder::Filters::Runner do
'receive_signed_only',
'receive_encrypted_only',
'receive_from_subscribed_emailaddresses_only',
'strip_html_from_alternative_if_keywords_present'
]
end
it 'loads custom filters from filters_dir even with non-2-digit priority' do
......@@ -145,6 +148,7 @@ describe Schleuder::Filters::Runner do
'receive_signed_only',
'receive_encrypted_only',
'receive_from_subscribed_emailaddresses_only',
'strip_html_from_alternative_if_keywords_present',
]
end
end
......
......@@ -73,4 +73,55 @@ describe Schleuder::Filters do
end
end
context '.strip_html_from_alternative_if_keywords_present' do
it 'strips HTML-part from multipart/alternative-message that contains keywords' do
list = create(:list)
mail = Mail.new
mail.to = list.email
mail.from = 'outside@example.org'
mail.text_part = content = 'x-resend: someone@example.org\n\nblabla'
mail.html_part = '<p>x-resend: someone@example.org</p><p>blabla</p>'
mail.subject = 'test'
mail.to_s
Schleuder::Filters.strip_html_from_alternative_if_keywords_present(list, mail)
expect(mail[:content_type].content_type).to eql('multipart/mixed')
expect(mail.parts.size).to be(1)
expect(mail.parts.first[:content_type].content_type).to eql('text/plain')
expect(mail.dynamic_pseudoheaders).to include('Note: This message included keywords and an alternating HTML-part. The HTML-part was removed to prevent the disclosure of these keywords to third parties.')
end
it 'does NOT strip HTML-part from multipart/alternative-message that does NOT contain keywords' do
list = create(:list)
mail = Mail.new
mail.to = 'schleuder@example.org'
mail.from = 'outside@example.org'
mail.text_part = content = 'Hello someone@example.org,\n\nblabla'
mail.html_part = '<p>Hello someone@example.org,</p><p>blabla</p>'
mail.subject = 'test'
Schleuder::Filters.strip_html_from_alternative_if_keywords_present(list, mail)
expect(mail[:content_type].content_type).to eql('multipart/alternative')
expect(mail.parts.size).to be(2)
expect(mail.parts.first[:content_type].content_type).to eql('text/plain')
expect(mail.parts.last[:content_type].content_type).to eql('text/html')
expect(mail.dynamic_pseudoheaders).to be_blank
end
it 'does not choke on nor change a message without Content-Type-header' do
mail = Mail.new
mail.to = 'schleuder@example.org'
mail.from = 'outside@example.org'
mail.body = 'blabla'
mail.subject = 'test'
Schleuder::Filters.strip_html_from_alternative_if_keywords_present(nil, mail)
expect(mail[:content_type]).to be_nil
expect(mail.parts.size).to be(0)
expect(mail.dynamic_pseudoheaders).to be_blank
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment