Build a Voting App .This was hard one... React Express

I needed about 3 months to finish this project.
Server side node.js, mongoose, express js, passport js , jwt.
Client side React and D3 plus bootstrap and react-bootstrap elements.

Solution: https://voting-up.herokuapp.com
GitHub Repository: https://github.com/GeorgeCrisan/voting-up

It is not mobile friendly as I did not invested time into css as much as I allocated for functionality, client side and server side.
Now mobile friendly and some css added.
Running with helmet contentSecurityPolicy and more security added.

Please let me know what you think.
Thank you.``

1 Like

I wish I were familiar with stuffs you used for back end, then could read and understand code to find out potential errors, security issues, etc. to report in more details.

But the bugs I found so far
First it’s about the createpoll gateway, as I checked the calls, this gateway accepts a JSON as input/parameter as following:

{
    "question": "ABC",
    "options": [{
        "optionBody": "A",
        "votes": 0
    }, {
        "optionBody": "B",
        "votes": 0
    }, {
        "optionBody": "C",
        "votes": 0
    }, {
        "optionBody": "ABC",
        "votes": 0
    }]
}

I just could override the votes value with something like 2000 and perform the query(check this), I’m not sure if it’s a bug! but if poll should starts from zero, you may not accept default poll state.

Same I could create a poll without any items (options:[]), you may confirm using this link

I then created another account(sample1), and created a poll(5b3cb7bbc9fbe50004665d59)
now another bad security bug
I could remove the poll I created with sample1 account, using another account(sample) by invoking the deletepoll and pass the id of poll sampl1 created. This is bad.

Now bugs about the updatePolls
The first thing I could do, is updating a pool state. let say a poll has 2000 votes for each index, it’s possible to override it by the bug exist in updatePolls
The bug is, instead you ask the server to add one to X index of Y poll, you just ask to update the poll state! This is not logical, please fix.
The bug let me to perform something like following:

{
    "voteNumbers": 0,
    "type": "public",
    "_id": "<<target id>>",
    "options": [{
        "_id": "<<index id 0>>",
        "optionBody": "A",
        "votes": 29
    }, {
        "_id": "<<index id 1>>",
        "optionBody": "B",
        "votes": 29
    }, {
        "_id": "<<index id 2>>",
        "optionBody": "C",
        "votes": 29
    }, {
        "_id": "<<index id 3>>",
        "optionBody": "ABC",
        "votes": 29
    }],
    "question": "ABC",
    "createdBy": "sample",
    "postTime": "2018-07-04T11:52:14.694Z",
    "__v": 0
}

I just could override the index labels using optionBody.

It seems your server just accept the JSOn from client, and just push it on backend database? no any checking on input data? No any check about permission? This is a very bad practice pal, please change your way coding the backend!

I won’t go more in detail since I just realized the server comes with lack of data checking, but my last check was about performing a bad-format data to check if it fails or not, so I just performed a bad request as following:

{
    "voteNumbers": 0,
    "type": "public",
    "_id": "<<target id>>",
    "options": [{
        "_id": "<<index id 0>>",
        "optionBody": "A",
        "votes": 2362463463473464327457436378458658634634782356232346
    }, {
        "_id": "<<index id 1>>",
        "optionBody": "B",
        "votes": 29
    }, {
        "_id": "<<index id 2>>",
        "optionBody": "C",
        "votes": "BAD_DATA"
    }, {
        "_id": "<<index id 3>>",
        "optionBody": "ABC",
        "votes": 29
    }],
    "question": "ABC",
    "createdBy": "sample",
    "postTime": "2018-07-04T11:52:14.694Z",
    "__v": 0
}

please considering the BAD_DATA which is not a valid, or a the first vote number value which is very huge, hopefully, both could not make crash for server.

I suggest you take the security issues really serious, just one script could make serious issues for you, and it may not happen first the first day you deploy, but it could be happened 2 year later where you have dedicated and important data, so that will be real trouble for you.

Keep goin on great work, happy programming.

2 Likes

I am finding your reply very helpful, I am going to correct tomorrow all the issues addressed above. I just read briefly but tomorrow when I have time I will check thoroughly. Really appreciate the effort and thank you.

I have learned that is much more easy to design your app with security checks in mind, rather than
finding bugs and having to figure it out how to rethink your functionality.
I am sure that there are other vulnerabilities as I have designed the application , initially , to fulfil user stories on freecodecamp and not security in terms of operations.

I have corrected the bugs as following.

For Create poll bugs.

  1. Create new poll does not accept default votes anymore.
    Solution: Server side correction for votes.
  2. Not allowed to create poll with empty options, less than 2 options, or options with white spaces only.
    Solution: Submit validation via regex.
    3.Not able to create poll for another account while logged from different account.
    Solution: Verify on server user identity before allowing operation.

UpdatePolls.

  1. Not able to override number of votes anymore, bad data problem corrected implicitly .
    Solution:

Poll.findOneAndUpdate({"_id":query,"options._id":query2},{"$inc": { "options.$.votes": 1 } },{new:true},function(err,data){
                      if(err){
                          console.log(err);
                        next(err);
                      }
                         
                       else {
                           console.log(data);
                        res.json({success: true, msg: 'Full update resolved',data:data});
                       }   
            });

Hello George,

Checking issues, bugs and vulnerabilities is much much easier to find out when you are the developer of back-end, rather than a client(like me) tries possibilities.

I might re check your work if I find any free time(so busy recently).

About the updates, I happy you could find them easily and got some move to fix them.

I suggest don’t use regex whenever you can use something else.

As I stated it before pal, I’m not node.js expert and fan, but if I were, I indeed went to source code rather production result to check functionalities.

Your website is still non-secure. I see your app identifies the user by authentication header key(don’t know if it binds it with a cookie? don’t think so!?). This header key is super easy to steal. Use HTTPs only cookies instead.

Also don’t know if your serve bind/lock client ip to the authentication or not.

Looks like none of your forms come with CSRF token, this is dangerous! Also make sure your server comes with same-policy origin.
Sine there is no CSRF token, and no same-origin policy, I could tell you someone could perform a vote from another page without even the target user gets notified.

Not sure, bu about any contact-like, or even create poll options(you may test it too), XSS could be applied. Always escape inputs before you send to the server. Or better option is not treat the requests from client with a format could be dangerous for server. Read about XSS to find out.

As you stated

Always have a paper, and write down what service you need to implement, specify the real inputs(not more, not less), and expected outputs.

Also if you think something could be hacked, or there is some vulnerabilities, so everyone else could find out that soon or later, so make a fix first.

Security stuffs is hard sometimes, assuming cipher downgrade when client initialized it with higher grade cipher(very rare). Not sure if it’s possible to check with node.js, but hope server itself identifies and do ssl session expiration. And more stuffs in security…

Keep going on great work, happy programming.

1 Like

http://voting-up.herokuapp.com/ I made it responsive and mobile friendly, next step is to add helmet and some features and to remove cors. If you are stuck at this challenge send me a reply as I am happy to help if needed.

Not the intended behaviour. I will look into it. Thank you.
Just got in my mind that I used react router and only made logic for client side router not serverside. This is why your request is failing. This is just an assumption late at night but I will be able to verify tomorrow.

Edit: as I said above, there is link for client side react router functionality.
My request to get the data is made at http://voting-up.herokuapp.com/allpolls .
New lesson learned.

Sorted out , solution is …

app.get('/*', function(req, res) {
  res.sendFile(path.join(__dirname, 'path/to/your/index.html'), function(err) {
    if (err) {
      res.status(500).send(err)
    }
  })
})