WordPress.org

Make WordPress Core

Opened 7 weeks ago

Last modified 7 weeks ago

#50441 new enhancement

Allow CORS for RSS feed

Reported by: stokito Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: Feeds Keywords: needs-privacy-review
Focuses: javascript Cc:

Description

I'm developing an in-browser RSS reader and want to get an RSS feed from my blog on WP.com but browser (both Chrome and FF) shows me the error:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://wordpress.com/blog/feed/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

Here is a small example to reproduce:

<html>
<head>
    <script src="https://unpkg.com/rss-parser/dist/rss-parser.min.js"></script>
    <script>
        let parser = new RSSParser();
        parser.parseURL('https://wordpress.com/blog/feed/', function(err, feed) {
            if (err) throw err;
            console.log(feed.title);
            feed.items.forEach(function(entry) {
                console.log(entry);
            })
        })
    </script>
</head>
</html>

This is quite popular thing that a lot of peoples tries to do:
https://www.google.com/search?q=wordpress+feed+cors

That's one of the main reasons why most browser JS RSS readers requires to use a dedicated proxy server that will make a server to sever call to retrieve the RSS:

The fix is easy:

add_action( 'pre_get_posts', 'add_header_origin' );

function add_header_origin() {
	if (is_feed()){
		header( 'Access-Control-Allow-Origin: *' );
	}
}   

But I wan't the fix to be added into WP trunk because my reader will mostly consume RSS from wordpress.com or many other WP blogs.

It should be fine to allow CORS requests to feed. The only one problem is a security concern. Hacker can make a DDoS by pasting on some popular site an <img> tag with src to WP feed and this will produce a big load to WP instance.
But here we can add a simple check: when browser requests an image it sends the header Accept: image/webp,image/apng,image/*,*/*;q=0.8 while JS RSS headers can set the Accept header manually to application/rss+xml.

Actually the rss-parser already sends the Accept: application/rss+xml. So on the server side we can just check that client requested exactly the feed and only then try to generate it.

As far I see this is something really important (because already used workarounds) and it should be easy to implement and safe to enable by default. So I'll set Major severity.

Change History (4)

#1 @ayeshrajans
7 weeks ago

  • Severity changed from major to normal

Welcome to WordPress Trac, @stokito.

The only one problem is a security concern. Hacker can make a DDoS by pasting on some popular site an <img> tag with src to WP feed and this will produce a big load to WP instance.

CORS doesn't protect the origins from DDoS attacks. Even without CORS headers, an attacker can simply use an img tag with the src set to the feed URL, and WordPress will happily serve the feed. The difference is that the caller cannot read the contents. Resources consumed in the victims server will be the same because as far as I know, WordPress does not serve different content with accept header negotiation.

I'm afraid the severity is used widely in WordPress trac to triage issues that break existing sites, and because this is a new feature, a major severity wouldn't help a lot for the other contributors.

It is not very common to serve CORS headers on feeds because traditionally, RSS readers always proxied the content, or consumed them server-side. At this point, I think this needs to be a decision the site owner has to make.

I'm not a core maintainer, so lets wait for one to make the decisions. I just wanted to put my thoughts forward.

#2 @stokito
7 weeks ago

Thank you Ayesh, good points. If WP works as you explained then this check for requested type should be added anyway. Or it may be implemented on some global filter/interceptor level: if request contains Accept: image/* but it requested not an image then decline it.
This doesn't protects for XSS with JS but at least it will protect from image tags on forum comments (like here) because src are not checked (they can actually check only that the url have extension png/jpg/webp).

I guess that browser may close connection after it received headers (and checked that there no cors-allow) so probably one of possible solutions may be to flush headers before generating payload.

Anyway, the fix is already used by a lot of peoples and there wasn't any problems.

traditionally, RSS readers always proxied the content, or consumed them server-side. At this point, I think this needs to be a decision the site owner has to make.

I guess this is "Chicken or the egg" problem here: people have to use a special RSS reader programs (which are almost all ugly) or use aggregators like Google Reader (that was killed to force users to use spying and addictive social networks) and Feedly.
WP is a biggest RSS producer in a Web. So just having CORS enabled will open a road for thousands of Web based RSS readers, like I trying to make for myself. My reader will save my subscriptions in browsers localStorage and fetch RSS directly without any spying aggregator's backend.

Site owners should be only happy that more peoples reads their content.

But here may come another problem: while there is only dozen of RSS aggregators and only several thousands of desktop/mobile RSS readers nobody ever had a huge load on RSS. So proper paging and caching should be implemented on browser side, but that already implemented and works fine out of the box.

#3 @ayeshrajans
7 weeks ago

Thanks for your reply. Because RSS is meant to me consumed by any software (in contrast to a private API that is consumed only by the app itself), I think it should be semantically secure to emit the CORS headers.

I created Fast404 (https://wordpress.org/plugins/fast404/) to immediately return a simple 404 message if the browser is expecting a static resource such as an image or a CSS file. I think this should be a separate discussion whether WordPress should care about the Accept header, because the routing and URL routing we have now is based on the URI only, and not the Accept headers. I created the plugin because I was annoyed at some random JPG 404 URLs triggered a full HTML page, but I don't know how it will be useful with other situations.

The other concern would be private content. If an RSS feed contains private content that is determined by a cookie (session cookies for example), a CORS-less feed would prevent the content from being read by a different site. Third party readers wouldn't send the cookies anyway, so it's safe.
If the feed emits CORS headers, this means the feed reader app can now read the same content the authenticated users get. This is of course very far fetched, but technically speaking, unless the user session cookie is SameSite=Strict, there is a non-zero chance of CORS headers enabling third party sites to read unauthorized content. A self-plug to a plugin that adds SameSite header to authentication cookies: https://wordpress.org/plugins/samesite/

#4 @stokito
7 weeks ago

Interesting plugin, I think I can port it's logic to Java. In the same time I'm pretty sure that just closing <img> attack vector will be fair enough. Anyway this is something out of the scope of the task and we should create a separate ticket for this.
Since you an author of Fast404, could you create such ticket to merge it's functionality into WP core?

If an RSS feed contains private content that is determined by a cookie

I'm pretty sure that WP doesn't have personal Atom/RSS feeds. But when they'll be implemented then all security measures should be applied.

Note: See TracTickets for help on using tickets.