1

I'm currently developing an API (node/express js) for a blog website that uses a markdown parser (showdown) for rendering content and a html sanitizer (html-santize) for removing malicious html/js.

Currently I am at the point where I want to let a user edit a post, but I do not want to expose "raw" content to other users other than the creator/owner of the blog-post.

Preferrably I would like to use the same route I use for retrieving raw data (GET /blog/:id?raw=true) which is harder to secure because they flow through the same controller, while raw=false would be a open route and raw=true would be a secured route. I could then fiddle around with some middlewares and stuff, but it all feels kind of hacky and I don't think it's good API design.

The other option I'm considering is implementing a new route (GET /blog/raw/:id), which would be easy to secure, but I would have 2 get-routes for the same resource in different shapes.

I know there isn't really a correct answer here, but I would like to hear your thoughts on this.

5
  • Are your users authenticating before calling the endpoint? If so, can't you just send different data if the authenticated user is the creator/owner.
    – Eric Stein
    Jun 22, 2017 at 16:35
  • @EricStein I'm using JWT tokens, so a user can either be authwnticated or not. In which case? Return rendered content anyway, altough someone is trying the retrieve the raw data if they are not authorized?
    – Alexander
    Jun 22, 2017 at 16:48
  • 2
    If the user has a JWT identifying them, and they are the owner/creator of the resource, reply to GET /blog/:id with the raw data. If they do not have a JWT, or they are not the owner/creator, reply to GET /blog/:id with the processed data.
    – Eric Stein
    Jun 22, 2017 at 17:09
  • @EricStein I know it would work like that. I was just hoping to get some alternative views on the matter because it doesn't feel like the best way to go, because it would introduce some security trickery and therefore a weakness imo.
    – Alexander
    Jun 22, 2017 at 17:53
  • I upvoted @EricStein . That is the way to do it, we don't know what ux you are using but still I would do as he suggests. Also there is No security hodge podge or trickery in his approach, clarify exactly why you think this is a bad idea.
    – RinkyPinku
    Oct 21, 2017 at 12:20

1 Answer 1

1

The usual design for an edit is to have GET /blog/:id/edit return an HTML page with the text box filled with the raw version, which then POST /blog/:id/edit would update it. You then secure the edit route. This route is generally used when you are working with a web browser directly navigating to it.

If you have a non-HTML front end (JavaScript, an app), giving you full control of how you talk to the Web API, you can instead use headers to ask for different rendering. It's usually considered better to pass only data into query parameters/post data while instructions for how to render (such as language choice, format) is usually better passed through headers, when you have the option.

For example, GET /blog/:id \\ Accept: text/html (where \\ is a newline) to get the rendered version and GET /blog/:id \\ Accept: application/json to get the raw version, and continue using PUT /blog/:id. If you don't want, or can't, use Accept (ie, because you're already returning JSON), you're free to create another header to communicate with your application, such as X-Post-Format: html and X-Post-Format: raw1. I wouldn't even secure the raw version at that point, just the POST/PUT, since the raw version is just a different format of the rendered version. Just sanitize the HTML before you store it.

How you do that for your specific language is a question for Stack Overflow.


1 The X- prefix is deprecated for header standards. It is marked as "SHOULD NOT", which means you can still use it if you want.

5
  • I do have a react front end, but prefer to keep the back end pure json. The reason I want the raw content to be secure is to allow the author to place comments for example. If you say the GET /blog/:id/edit and POST /blog/:id/edit is the usual design pattern for this, I think this is the way to go. Would using PUT /blog/:id to update instead be a bad practice in this case? It feels cleaner.
    – Alexander
    Jun 22, 2017 at 18:14
  • @Alexander Understood as to why you'd want to secure it in that way. I'd still allow raw to return the unmarked up version regardless, but strip out non-renderables like comments if the user isn't authenticated. Showing different results to different people for the same route is perfectly fine. I have updated my answer with an additional possibility based on your reply.
    – Kevin Fee
    Jun 22, 2017 at 18:22
  • @Alexander the reason I suggest allowing a public version of the raw is so that if you or someone else wants to make a different consumer (an app, let's say) that they think it would be better if they process the markdown themselves, you should allow them the option.
    – Kevin Fee
    Jun 22, 2017 at 18:26
  • I think that would make it unnecessarily complicated for my use case. I want to save the raw as is provided, this means leaving in potentially malicious JavaScript as well, that is stripped out by my parser/sanitizer on requesting the processed data. Leaving it up to others to clean the raw data would be irresponsible. It is recommended for markdown to sanitize the html after parsing it, that is why sanitized markdown isn't really an option.
    – Alexander
    Jun 22, 2017 at 20:25
  • Mostly a good answer, my only caveat is that in my experience the API standard seems to be a POST to /thing/:id, not a POST to /thing/:id/edit.
    – Paul
    Jul 23, 2017 at 10:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.