# Secure Uploads

**URL:** https://meta.discourse.org/t/secure-uploads/140017
**Category:** Announcements
**Tags:** secure-uploads
**Created:** [January 29, 2020, 5:14am UTC](https://meta.discourse.org/t/secure-uploads/140017 "2020-01-29T05:14:56Z")
**Posts on this page:** 20
**Page:** 2

<div class="post-metadata">

### Author: ![rmbolger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rmbolger/32/202435_2.png) [@rmbolger](https://meta.discourse.org/u/rmbolger)
#### Post date: [March 24, 2021, 6:51am UTC](https://meta.discourse.org/t/secure-uploads/140017/106 "2021-03-24T06:51:34Z")

</div>

For a completely private forum (no anonymous access), the lack of a secure media option in the default local storage configuration seems like a huge oversight to me. I wouldn’t be surprised if a lot of folks running private forums don’t realize that all of their post attachments are publicly accessible (if you know the URL). If my post’s text can’t be accessed anonymously, intuitively I would think the post’s attachments can’t be either.

> [@martin](#):
>
> I do not think we have plans at this time to modify how this works; I think there would be quite a bit of work involved to avoid using ACLs altogether for S3 replacement

Is it worth submitting an issue requesting this to see what sort of support it would get? Does one already exist? This one issue is currently a deal breaker for my small, poor group who is trying to spin up Discourse in an environment where we own the hosting hardware already and don’t want to pay for cloud storage (particularly at AWS S3 prices) just to make sure our media isn’t viewable anonymously.

Also, forgive the potential naivete of this question. But there is already support for distinct buckets for uploads and backups, right? Would it be difficult to support a third bucket for secure uploads? Public uploads go in the public bucket, secure uploads go in the secure bucket, and no individual object ACLS are needed. And if the security status of an object changes, it could just be moved between buckets?

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [March 24, 2021, 12:12pm UTC](https://meta.discourse.org/t/secure-uploads/140017/107 "2021-03-24T12:12:30Z")

</div>

I think it’s quite a bit of work. At least a day’s work, but maybe a week?

Cdck hosting, which pays for development, is run with uploads on S3, so it’s only login required self hosted sites without budget for S3 that’s interested.

If your users see sharing links to your assets they could just as well be downloading them to share them. It doesn’t seem like a big problem.

---

<div class="post-metadata">

### Author: ![rmbolger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rmbolger/32/202435_2.png) [@rmbolger](https://meta.discourse.org/u/rmbolger)
#### Post date: [March 24, 2021, 4:12pm UTC](https://meta.discourse.org/t/secure-uploads/140017/108 "2021-03-24T16:12:04Z")

</div>

I’m not crazy pants for thinking it’s weird that post text is protected but attachments are not though, right?

> [@pfaffman](#):
>
> If your users see sharing links to your assets they could just as well be downloading them to share them. It doesn’t seem like a big problem.

There’s a big difference between intentional and accidental sharing though. Obviously, there’s no real way to prevent the former. But the latter can happen right now simply because people don’t understand the underlying tech. Consider email notifications for posts that include links to attached images getting innocently forwarded to non-members. An option to redact attachments in emails that’s not tied to the secure media functionality might be a good alternative there.

Even when people do intentionally share attachment links, they might have simply forgotten that it was from a protected category. But in an ideal world, the attachment link should be worthless to anyone without access to that category.

A current or future bug in one of the S3 implementations could also potentially allow for anonymous enumeration of the resources in a bucket or the ability to guess and brute force object URLs. In an ideal world, I’d want my on-prem S3 interface to be firewalled off from the internet at large so only the Discourse server can reach it directly.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [March 25, 2021, 5:18am UTC](https://meta.discourse.org/t/secure-uploads/140017/109 "2021-03-25T05:18:22Z")

</div>

> [@rmbolger](#):
>
> I’m not crazy pants for thinking it’s weird that post text is protected but attachments are not though, right?

Not crazy, implementing secure uploads for non s3 setups is certainly not something I am against building. It is just that we have no urgency or push to build the feature and the change is non trivial.

We occasionally have interns and audition projects, this is certainly a type of project that could fit into one of those buckets.

---

<div class="post-metadata">

### Author: ![rmbolger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rmbolger/32/202435_2.png) [@rmbolger](https://meta.discourse.org/u/rmbolger)
#### Post date: [March 25, 2021, 5:34pm UTC](https://meta.discourse.org/t/secure-uploads/140017/110 "2021-03-25T17:34:33Z")

</div>

> [@rmbolger](#):
>
> Would it be difficult to support a third bucket for secure uploads? Public uploads go in the public bucket, secure uploads go in the secure bucket, and no individual object ACLS are needed. And if the security status of an object changes, it could just be moved between buckets?

Any thoughts on the feasibility of this as an easier path for secure media on not-AWS-S3 storage?

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [March 30, 2021, 6:27pm UTC](https://meta.discourse.org/t/secure-uploads/140017/113 "2021-03-30T18:27:13Z")

</div>

I’ve got a quick hack that I think would provide secure uploads for login-required sites.

Basically, you set up [Authentication Based on Subrequest Result | NGINX Documentation](https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/) for uploads. The only issue is that I can’t find a URL that returns a 403/401 when login-required is turned on, so accessing an upload when you’re not logged in gives a 500 error. This would only happen if someone had an upload URL and tried to access it when they weren’t logged in, so it doesn’t seem that bad.

It’s something like this:

```plaintext
# JP
    location = /auth {
        internal;
        proxy_pass http://discourse/categories;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URI $request_uri;
    } 
    # END JP
    location ~ ^/uploads/ {

      auth_request /auth; #$JP
      # NOTE: it is really annoying that we can't just define headers
      # at the top level and inherit.
      #

```

---

<div class="post-metadata">

### Author: ![martin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/martin/32/491371_2.png) [@martin](https://meta.discourse.org/u/martin)
#### Post date: [March 30, 2021, 10:48pm UTC](https://meta.discourse.org/t/secure-uploads/140017/114 "2021-03-30T22:48:36Z")

</div>

We have no plans to make distinct bucket functionality for secure uploads, nor do we have plans to make secure uploads work with non-S3 setups or setups without ACLs. We may look at doing this in the future if there is sufficient demand for this work to a point where it makes sense for us to devote time and resources to this effort.

---

<div class="post-metadata">

### Author: ![HashHackers](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/hashhackers/32/209405_2.png) [@HashHackers](https://meta.discourse.org/u/HashHackers)
#### Post date: [April 15, 2021, 3:15am UTC](https://meta.discourse.org/t/secure-uploads/140017/115 "2021-04-15T03:15:56Z")

</div>

why its using `https://hashhackersforum.s3.us-east-2.amazonaws.com/optimized/2X/3/3204e85df407adfce19e105308248aee8b3b3f57_2_690x424.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAU5WBGG5Z7FNHQEIS%2F20210415%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20210415T025617Z&X-Amz-Expires=300&X-Amz-SignedHeaders=host&X-Amz-Signature=15c9118929ccd9c24a9594ab02a47e900269b9d921d41679a317e29d6174c2bc`  
instead of `https://forum.cdn.hashhackers.com/optimized/2X/3/3204e85df407adfce19e105308248aee8b3b3f57_2_690x424.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAU5WBGG5Z7FNHQEIS%2F20210415%2Fus-east-2%2Fs3%2Faws4_request&X-Amz-Date=20210415T025617Z&X-Amz-Expires=300&X-Amz-SignedHeaders=host&X-Amz-Signature=15c9118929ccd9c24a9594ab02a47e900269b9d921d41679a317e29d6174c2bc`

while i’ve entered CDN URL correctly.

---

<div class="post-metadata">

### Author: ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)
#### Post date: [April 15, 2021, 3:44am UTC](https://meta.discourse.org/t/secure-uploads/140017/116 "2021-04-15T03:44:26Z")

</div>

It won’t use a CDN if you enable “Secure Media Uploads”.

---

<div class="post-metadata">

### Author: ![bigfudge](https://avatars.discourse-cdn.com/v4/letter/b/6de8d8/32.png) [@bigfudge](https://meta.discourse.org/u/bigfudge)
#### Post date: [April 23, 2021, 4:19pm UTC](https://meta.discourse.org/t/secure-uploads/140017/117 "2021-04-23T16:19:07Z")

</div>

One thing I’ve noticed is that the admin section warns that

> The server is configured to upload files to S3, but there is no S3 CDN configured. This can lead to expensive S3 costs and slower site performance. [See “Using Object Storage for Uploads” to learn more](https://meta.discourse.org/t/-/148916).

I don’t mind ignoring it, but we have secure media enabled which means it’s not possible to use a CDN. This message probably shouldn’t be shown on sites with `secure_media` enabled.

---

<div class="post-metadata">

### Author: ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)
#### Post date: [April 23, 2021, 4:28pm UTC](https://meta.discourse.org/t/secure-uploads/140017/118 "2021-04-23T16:28:48Z")

</div>

> [@bigfudge](#):
>
> I don’t mind ignoring it, but we have secure media enabled which means it’s not possible to use a CDN.

A CDN can still be used for all the JS assets, making your site a lot faster to render for users around the world.

---

<div class="post-metadata">

### Author: ![bigfudge](https://avatars.discourse-cdn.com/v4/letter/b/6de8d8/32.png) [@bigfudge](https://meta.discourse.org/u/bigfudge)
#### Post date: [April 24, 2021, 7:22am UTC](https://meta.discourse.org/t/secure-uploads/140017/119 "2021-04-24T07:22:59Z")

</div>

That’s cool. It wasn’t clear to me that discourse would treat the static assets differently. I think I need to read all the threads here again.

---

<div class="post-metadata">

### Author: ![danilogit](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/danilogit/32/220801_2.png) [@danilogit](https://meta.discourse.org/u/danilogit)
#### Post date: [May 26, 2021, 3:59pm UTC](https://meta.discourse.org/t/secure-uploads/140017/120 "2021-05-26T15:59:13Z")

</div>

After I upgraded to **2.8.0.beta1** version, my **badges** using authenticated S3 Urls are not working. It was OK before the upgrade.

I checked the table **uploads** and the value for column secure is **true**.

 ![image](https://global.discourse-cdn.com/meta/original/3X/d/c/dcb62e0f7f23970b0bc3b2f6a4e48f469f6ccf68.png)

Even after uploading a file using the option **New Badge** the image preview was kept empty.

 ![image](https://global.discourse-cdn.com/meta/original/3X/c/e/ceca58b6a20a1a83f8df86b35974f5c56fe433aa.png)

No problems with other files using S3 url so far.

Any help? Thank you! 😉

---

<div class="post-metadata">

### Author: ![martin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/martin/32/491371_2.png) [@martin](https://meta.discourse.org/u/martin)
#### Post date: [May 27, 2021, 5:00am UTC](https://meta.discourse.org/t/secure-uploads/140017/121 "2021-05-27T05:00:03Z")

</div>

Ah…yet another place that is making secure uploads that shouldn’t be. Badges should not be marked secure because they are essentially public images, like avatars, category logos, and other things. I will need to do a fix to make sure that badge images are not marked secure and a migration script that fixes ones that are already secure.

I am surprised this was working for you at all, nothing in 2.8.0 should have affected this.

---

<div class="post-metadata">

### Author: ![danilogit](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/danilogit/32/220801_2.png) [@danilogit](https://meta.discourse.org/u/danilogit)
#### Post date: [May 27, 2021, 11:58am UTC](https://meta.discourse.org/t/secure-uploads/140017/122 "2021-05-27T11:58:08Z")

</div>

Hello @martin

Thank you for your reply. This is my first time using Ruby and I am delighted how clear this language can be. After some hours debugging I believe I found where to look. I guess I did the opposite you said 🙂 I put some lines in the Badge model and now it can load the images. I also see that we have a flag **for\_site\_setting** there. I believe it relies on this information to adjust the ACL for objects on S3, and set false for that column.

**app/models/badge.rb**

```ruby
  def image_url
    if image_upload_id.present?
      return upload_cdn_path(image_upload.url) if !image_upload.url.include?(SiteSetting.Upload.absolute_base_url)
      uri = URI.parse(image_upload.url)
      Rails.application.routes.url_for(
        controller: "uploads",
        action: "show_secure",
        path: uri.path[1..-1],
        only_path: true
      )
    end
  end

```

I will have a look what will change in the next upgrade to learn more about that.  
Could you tell me what is the best version to use in production ?

Thank you!

I hope I can contribute more in the code base in the future.

---

<div class="post-metadata">

### Author: ![martin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/martin/32/491371_2.png) [@martin](https://meta.discourse.org/u/martin)
#### Post date: [May 28, 2021, 12:03am UTC](https://meta.discourse.org/t/secure-uploads/140017/123 "2021-05-28T00:03:40Z")

</div>

Hey @danilogit,

The change you made to the badge model will certainly work, and it’s great that you were able to put that together the first time you used ruby! Though I will still go ahead and fix the core issue where badges shouldn’t be marked as secure.

> [@danilogit](#):
>
> I will have a look what will change in the next upgrade to learn more about that.  
> Could you tell me what is the best version to use in production ?

Our `tests-passed` branch is the best version to use in production because that will get all the latest fixes as soon as they are available, though some people may prefer to stay on the beta branch which gets fixes and changes every few weeks or so.

I’ll let you know when I have the fix for badges being marked as secure done.

---

<div class="post-metadata">

### Author: ![martin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/martin/32/491371_2.png) [@martin](https://meta.discourse.org/u/martin)
#### Post date: [May 28, 2021, 3:15am UTC](https://meta.discourse.org/t/secure-uploads/140017/124 "2021-05-28T03:15:31Z")

</div>

I finished a fix for this issue today:

[https://github.com/discourse/discourse/pull/13193](https://github.com/discourse/discourse/pull/13193)

cc @danilogit

---

<div class="post-metadata">

### Author: ![bigfudge](https://avatars.discourse-cdn.com/v4/letter/b/6de8d8/32.png) [@bigfudge](https://meta.discourse.org/u/bigfudge)
#### Post date: [September 10, 2021, 8:46am UTC](https://meta.discourse.org/t/secure-uploads/140017/125 "2021-09-10T08:46:59Z")

</div>

I just posted this,

> [@S3 Errors Uploading Profile Photos](https://meta.discourse.org/t/s3-errors-uploading-profile-photos/203063/7):
>
> Can confirm that when I try to upload an avatar the progress bar updates, and gets to 100%, but only then says “Error: Access Denied”. Looking in the js console, I get the error: https://discourse.psy.plymouth.ac.uk/uploads.json?client\_id=0a2569993a6b43d6b5f8c60fdd2c913e Failed to load resource: the server responded with a status of 422 () And if I follow that url: {"errors":["The requested URL or resource could not be found."],"error\_type":"not\_found"} Checking the S3 bucket, nothing has m…

…but wonder if the issue is related to your comment here?

Is it supported to have users upload avatars when secure media uploads is turned on? At present I’m getting an error, but wonder if this is because avatars are uploaded to the same bucket where public access is not allowed…

---

<div class="post-metadata">

### Author: ![Canapin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/canapin/32/119591_2.png) [@Canapin](https://meta.discourse.org/u/Canapin)
#### Post date: [July 25, 2023, 11:26am UTC](https://meta.discourse.org/t/secure-uploads/140017/126 "2023-07-25T11:26:11Z")

</div>

3 posts were split to a new topic: [Can I use secure media and page publishing simultaneously in Discourse?](https://meta.discourse.org/t/can-i-use-secure-media-and-page-publishing-simultaneously-in-discourse/272753)

---

<div class="post-metadata">

### Author: ![martin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/martin/32/491371_2.png) [@martin](https://meta.discourse.org/u/martin)
#### Post date: [October 24, 2022, 3:42am UTC](https://meta.discourse.org/t/secure-uploads/140017/129 "2022-10-24T03:42:42Z")

</div>

I recently renamed “secure media” and related settings to “secure uploads” since it doesn’t just apply to images/video etc., and everyone generally refers to it as secure uploads anyway. The relevant core commit is here:

[https://github.com/discourse/discourse/pull/18376](https://github.com/discourse/discourse/pull/18376)

This OP of this topic has now been updated to reflect this.

[Previous page](https://meta.discourse.org/t/secure-uploads/140017.md?page=1)

[Next page](https://meta.discourse.org/t/secure-uploads/140017.md?page=3)
