Category not accepting "anonymous email" from known users

AI-generated summary

The discussion centers on a bug where Discourse rejects emails from known users who lack permission to post in a private category, while accepting emails from anonymous users. The original reporter, downey, outlines that emails from unregistered addresses work, but those from registered non-members are rejected with a can_create? failed error. zogstrip confirms this is intentional behavior: the system associates the email with the user first, then checks permissions. Since the user is not in the allowed group, the post is blocked. The email_in_allow_strangers setting currently only applies to staged (unactivated) users.

Several users, including wityr and Christian_Kindel, argue this is counter-intuitive and problematic, especially for mailing list mirrors where known subscribers are blocked while unknown senders are accepted. dachary proposes code patches to bypass validation when email_in_allow_strangers is enabled, though sam explains that the current restriction is a security measure to prevent email spoofing and impersonation. Sam suggests a long-term solution involving a verification step where the user confirms the email was sent by them.

Other participants, such as Simon_Manning, argue that modern email authentication protocols like SPF, DKIM, and DMARC provide sufficient protection against spoofing, suggesting that the system could safely accept emails from known users if these checks pass. sam considers adding a site setting to allow operators to accept this risk. Simon_Manning further clarifies that the issue is specific to private categories; in public categories, known users with permissions can post via email without issue. The consensus among developers is that fixing this requires a comprehensive approach to security, potentially leveraging email authentication results to allow known users to post in restricted categories without compromising safety against impersonation. The issue persists in recent versions, affecting projects like the Tor Forum that rely on email-to-forum functionality.

Reproduce:

  1. Have a “private” category that only has create/reply/see access for members of a specific group. No other permissions.
  2. Enable “anonymous email in” for that specific via a unique working alias to the incoming POP account.
  3. Have a non-staff user that is not a member of the group send an email report in to the category email address from the email address associated with their account.
  4. Send in an email from an account not associated with any known Discourse account.

Expected Behavior:

  • Both #3 and #4 result in new topics in the private category, and the group can begin discussion.

Actual Behavior:

  • The email in #4 works but email in #3 is rejected with the can_create? failed error.
8개의 좋아요

@zogstrip can you review this?

Is this still a problem?

I’m no longer running a site with incoming email enabled so unfortunately can’t reproduce to say either way.

2개의 좋아요

Pretty sure #3 still isn’t working.

When we receive an email, we first try to associate it to a user, and then we check for permissions. Since the user isn’t part of the group, they can’t post.

The email_in_allow_strangers field on the category only works for staged users.

3개의 좋아요

Can confirm #3 still not working. Is the best workaround right now to have emails directed at a group rather than a category? Not my preferred arrangement but I can switch until a patch comes out.

1개의 좋아요

I don’t think we can ever support #3 unless we add another setting that opens up any incoming emails?

This scenario seems to be replaced these days with the group functionality as a type of workaround, although I could see some use cases that it might still be just as valuable for categories/topics/discussions.

Sounds plausible. Is this a big thing to do?

Like you say, this is just a (bad) workaround. IMO this should be controllable on a per-category level. Clearly a bug that this works only for anonymous but not for known users.

1개의 좋아요

I just ran into this issue while trying to set up a category for our organizations info list. This category only allows a certain group to access it, but we selected the option to allow emails from anonymous users. Email addresses that are not associated with any of our discourse users can send a message that will show up in the category, but registered users that are not in the group get rejected due to “Insufficient Trust Level”. I think I understand the technical reason why it works this way (only works for staged users) but is there a reason why this would be the desired or expected behavior? It seems to me if we are choosing to allow anonymous users we probably want to allow all registered users as well.

1개의 좋아요

저희 사이트에서도 지난주에 동일한 문제를 겪었습니다. 저희의 상황은 다음과 같습니다.

대부분의 카테고리는 등록된 사용자만 사용할 수 있도록 설정되어 있지만, 커뮤니티의 비회원인 사용자가 핵심 개발자에게 이메일을 보내 간단한 질문을 하거나 우려 사항을 제기할 수 있는 방법을 마련하고 싶었습니다.

이를 위해 익명 사용자의 이메일을 받을 수 있는 카테고리를 설정하고 커스텀 주소(예: ourproject+contact@discoursemail.com)를 사용했습니다. 커뮤니티 전체에 너무 많은 메일이나 노이즈를 생성하지 않도록, 해당 카테고리의 읽기 권한은 핵심 프로젝트 멤버에게만 부여했습니다. (읽기 접근을 제한하면 생성/답변 접근도 함께 제한되므로, 핵심 멤버가 주제 생성과 답변도 할 수 있도록 해야 했습니다.)

하지만 익명 사용자가 공식 계정을 생성하면 더 이상 해당 연락처 이메일 주소로 메일을 보낼 수 없다는 사실을 알게 되었습니다. 이는 직관에 반하는 것으로, 이전보다 더 공식적이고 등록된 상태가 되었음에도 불구하고 오히려 이전보다 할 수 있는 일이 줄어든 상황이 되기 때문입니다.

이 주제에 도달하기 전까지 이 문제로 인해 상당한 혼란을 겪었으며, 여전히 불행한 상황이라고 생각합니다.

-Brad

2개의 좋아요

이 문제는 2.7.8 버전에서도 여전히 존재합니다. 발신자가 포럼에 등록된 계정이 없을 때 카테고리와 연관된 이메일 주소로 전송된 메일이 수락되고, 등록된 계정이 있을 경우 거부되는 점은 혼란스럽습니다.

3개의 좋아요

다음 패치(현재 main 브랜치 대상)가 카테고리에서 email_in_allow_strangers가 설정된 경우, 단계적 사용자(staged users)에게 적용되는 방식과 동일한 방식으로 유효성 검사를 건너뛰어 이 문제를 해결할 수 있다고 생각합니다. 이 방식이 타당해 보이나요?

diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb
index 7c76c44d61..dd3bc3cfb0 100644
--- a/lib/email/receiver.rb
+++ b/lib/email/receiver.rb
@@ -762,7 +762,7 @@ module Email
                      elided: elided,
                      title: subject,
                      category: destination.id,
-                     skip_validations: user.staged?)
+                     skip_validations: (user.staged? || destination.email_in_allow_strangers))
 
       elsif destination.is_a?(PostReplyKey)
         # We don't stage new users for emails to reply addresses, exit if user is nil

동작하지 않는 이유는 **검증(validations)**이 게시글의 내용에 관한 것이지, 게시글을 생성할 권한이 있는지 여부에 관한 것이 아니기 때문입니다…

아래 패치를 테스트해보니 동작하는 것을 확인했습니다. 이것은 해킹이므로 집에서 시도하지 마세요 :scream: 그 장점은 변경 사항이 어디에서 발생해야 하는지를 대략적으로 파악할 수 있다는 점입니다. 도전 과제는 이를 적절하게 수행하는 방법을 알아내는 것입니다. 조언이 있다면 환영합니다 :pray:

diff --git a/app/jobs/regular/notify_mailing_list_subscribers.rb b/app/jobs/regular/notify_mailing_list_subscribers.rb
index c535296105..1d3bf79637 100644
--- a/app/jobs/regular/notify_mailing_list_subscribers.rb
+++ b/app/jobs/regular/notify_mailing_list_subscribers.rb
@@ -74,7 +74,7 @@ module Jobs
 
       DiscourseEvent.trigger(:notify_mailing_list_subscribers, users, post)
       users.find_each do |user|
-        if Guardian.new(user).can_see?(post)
+        if Guardian.new(user).can_see?(post) && Guardian.new(user).can_see_category_staged?(post.topic.category)
           if EmailLog.reached_max_emails?(user)
             skip(user.email, user.id, post.id,
               SkippedEmailLog.reason_types[:exceeded_emails_limit]
diff --git a/app/models/category.rb b/app/models/category.rb
index 630a74c425..6c253650c6 100644
--- a/app/models/category.rb
+++ b/app/models/category.rb
@@ -201,7 +201,7 @@ class Category < ActiveRecord::Base
       end
     else
       permissions = permission_types.map { |p| CategoryGroup.permission_types[p] }
-      where("(:staged AND LENGTH(COALESCE(email_in, '')) > 0 AND email_in_allow_strangers)
+      where("(LENGTH(COALESCE(email_in, '')) > 0 AND email_in_allow_strangers)
           OR categories.id NOT IN (SELECT category_id FROM category_groups)
           OR categories.id IN (
                 SELECT category_id
@@ -209,7 +209,6 @@ class Category < ActiveRecord::Base
                  WHERE permission_type IN (:permissions)
                    AND (group_id = :everyone OR group_id IN (SELECT group_id FROM group_users WHERE user_id = :user_id))
              )",
-        staged: guardian.is_staged?,
         permissions: permissions,
         user_id: guardian.user.id,
         everyone: Group[:everyone].id)
diff --git a/lib/guardian/category_guardian.rb b/lib/guardian/category_guardian.rb
index 94a48466d6..2a4ba8015c 100644
--- a/lib/guardian/category_guardian.rb
+++ b/lib/guardian/category_guardian.rb
@@ -64,6 +64,14 @@ module CategoryGuardian
   end
 
   def can_see_category?(category)
+    return false unless category
+    return true if is_admin?
+    return true if !category.read_restricted
+    return true if category.email_in.present? && category.email_in_allow_strangers
+    secure_category_ids.include?(category.id)
+  end
+
+  def can_see_category_staged?(category)
     return false unless category
     return true if is_admin?
     return true if !category.read_restricted
2개의 좋아요

@zogstrip, 이 제안에 대해 어떻게 생각하세요?

1개의 좋아요

여기서 관찰되는 동작은 의도적인 것으로 보입니다. 따라서 수정 작업은 꽤 광범위하게 이루어져야 할 것입니다.

기존 계정에 주제를 연결할 수 있도록 허용하는 문제는 누구나 다른 사람의 이메일을 위장할 수 있다는 점입니다.

장기적으로 이 문제를 해결하는 방식은 다음과 같아야 한다고 생각합니다:

  1. sam@somewhere.com이 Discourse에 계정을 보유하고 있습니다.
  2. sam@somewhere.com이 anonymous email in이 포함된 카테고리에 이메일을 보냅니다.
  3. Discourse가 sam@somewhere.com에게 이메일을 보냅니다: “다음 게시물을 작성한 것 같습니다: 게시 내용, Discourse URL. 정말 당신이었나요?”
  4. '예’를 클릭합니다.
  5. 주제가 생성됩니다.

이런 보호 장치가 없다면 이 기능은 사칭에 완전히 노출되어 매우 위험합니다.

5개의 좋아요

계정이 없는匿名用户에게서 이메일을 받기 파라미터와 무관하게, 이 문제는 이미 존재하지 않나요?

저는 이 의견에 공감합니다: 이메일이 카테고리와 연결되어 있고 계정이 없는匿名用户에게서 이메일을 받기 상자가 체크된 경우, 들어오는 이메일은

  1. Discourse 계정에 연결되어 있고
  2. 카테고리의 보안 파라미터에 따라 메시지 읽기가 허용되지 않는 사용자로부터 온 것이라면

수락되어야 합니다.

1개의 좋아요

2016년에 비해 현재 훨씬 더 널리 사용되고 있는 SPF/DKIM/DMARC가 이러한 문제를 충분히 잘 방지하지 않을까요?

사용자를 위한 모든 양질의 이메일 제공업체는 해당 사용자의 소유가 아닌 주소로 다른 사용자가 메일을 보내는 것을 허용하지 않으며, Discourse 인스턴스를 위한 모든 양질의 이메일 제공업체 또는 수신 서비스는 출처 검증에 실패한 메일을 거부해야 합니다.

발신자 주소를 검증하지 않고 SPF 등의 레코드를 설정하지 않는 제공업체도 존재하지만, 사용자가 위장 공격에 대한 어떠한 보호 조치도 취하지 않는 이메일 제공업체를 선택한다면, 그 사용자가 위장당할 수 있는 것은 합리적인 결과라고 볼 수 있습니다.

상세히 파고들지는 않았지만, Email::AuthenticationResults가 이미 출처 검증을 일부 수행하는 것으로 보입니다. 단기적으로는(혹은 좀 더 짧은 기간 동안) 판정 결과가(아직 제공되지 않는다면) 제공되도록 하여, pass 판정을 받은 이메일을 수용할 수 있도록 하면 좋을 것 같습니다.

장기적인 해결책에서는 pass 판정인 경우 "정말 당신인가요?"라는 인증 과정을 건너뛰도록 할 수도 있습니다.