I’m creating a form that lets members of an organization update their personal data in the member data base. Since including sensitive data in query links is insecure and forbidden, I created a way around this issue and would like to hear some feedback now from the security experts among us.
This is my idea:
- Generate a hash value column from all other columns for each row in the “personal data” table
- Send an email to every member with a link to the form of the “updated personal data” table and only the hash value ID as a pre filled, hidden, lookup value
- Pull all current sensitive data into the form as related columns of the ID lookup
- Let members submit their updated data, so you can override the original table after you checked the submissions
This is my doc:
Published Doc Link
I haven’t implemented the mail feature in this show doc, but you can click the individual form links.
Since it is necessary to include all lookup columns in the security settings, I have a few concerns:
- Is it possible for people with one link to show the hidden ID column and to select one of the other lookup IDs?
- Is the lookup table or the table behind the form accessable with simple hacking skills like sql injection?
- Would it improve the security to not store the hash values in the table but to evaluate them just in time?
- Is it still insecure to send those sensitive data back and forth via forms?
Thank you very much in advance,
hi @M_Schneider ,
It looks good to me, though I am not a security expert. My experience with forms and data exchange is that most of the time the data is visible in the URL and ‘it people’ are concerned about the row Id’s and try to find a way around it (row id or alternatives as key) to disable the option to empty their base via creative browsing.
For example, when using Paperform with Coda via Zapier the data is in the open and I guess this is what Coda is warning for.
I am not sure how ‘easy’ someone can translate the valus back to ‘human readable values’. How do you do that in Coda by the way in case you would need to?
Second, how are you matching the updated values with the existing ones? Based on what?
I added the Crypto::SHA256() to a form URL and noticed that if you have one empty value, this logic breaks. For example if you have a field for comments and nothing is written, the link is broken. How would you suggest to work around this? Maybe an automation that first fills out something before encrypting it?
1 ) Yes you can add any kind of ID as matching value, once hashed it seems to me not so important what kind of ID you use like RowId / Created / Random Integer (via an automation) or a combi of these.
2) I don’t know
3) everything you can do on the flow is better for performance I guess, once some one is in your table everything is in the open.
4 ) if you can make sure that every bit of data is encrypted in the URL, I would consider it as okay. As said before the main worry is that most of the time, the data is very well readable transmitted.
I just tried to create a URL based on your idea to apply
Crypto::SHA256(), but it appears it doesn’t work like that. I created a functioning URL , but it did not pre-fill, so I am afraid this trick won’t work.
Maybe others have insights I overlook
And if it does not work, the main issue remains, data flows over the internet. I am using these forms for simple things like feedback on calculations, reservations, evaluations etc
Hey @Christiaan_Huizer ,
thanks for your commitment! Did you copy my doc for testing? This should give you a little more detailled insight in my work and how I made the links work.
Since there aren’t that many columns I matched the columns by hand, this formula can be found in the “update original table” button column.
The hashes practically can’t be translated back, a randomly generated key would also work in this case, but I wanted it to be deterministic and reproducable.
Thanks for showing me that bug, it always appeared when changing data, but the new link began to work a few seconds after the change.
- Seems like I phrased my question wrong, I wanted to know if it is possible for attackers to make them visible.
- From the performance point of view it should be more efficient to use pre calculated values from a table, but yes, that was my concern.
- The data that gets pulled via lookup is not encrypted (by me)
Sure, the data also travels over the internet when I’m working on my doc, but in this case I’m quite positive that it is encrypted. The question is, how is the lookup traffic protected?
I am afraid I misunderstood you, I assumed you wanted to use a form outside Coda, but if I understand correctly you want to invite all the users in the doc and you do not want to see them values you pull in via the lookup. Correct?
I can read all the values in the doc without copying the doc, but if you open it, I can enter it
Hey @Christiaan_Huizer ,
no you didn’t, I do want to use the form outside of Coda. But yes, I want people to see only the lookup values that are connected to the ID of their link. If I made the ID column visible, everyone would be able to select every ID in the table.
Please copy it for yourself if you want to take a look under the hood, I don’t want people to make changes on this one.
Maybe I didn’t make myself clear, the doc already performs exactly like I want it to and I can’t detect any security issues by myself. That’s why I need some security experts or Codans to take a look on it and try to “attack” it.
Hackers would also have these information about codas technology.
TL;DR: Commendable effort but it solves nothing.
The “Update your data” form is insecure because you had to enable “Include lookup data” for the formulas to work, and that included the whole table of Personal Data (and also of the Updated Personal Data) in the shard that gets sent to the client where any attacker can crack it easily:
So, the only way to publish the form securely is to not include any existing data, no formulas or whatnot — only the fields to fill out.
At that point, SHA256 seems an unnecessary complication. If you wanted a pseudorandom row ID that would be hard to guess, you could use the
Split(thisRow + "", "/").Last() idiom to get row UID — it is statistically enough. If you additionally wanted to prevent accidental form resubmissions, you could additionally include a version/timestamp parameter to catch those and not apply.
I think the solution has to come from Coda:
- you need to be able to share pages (or sections) rather than a complete doc
- the filtering should take place at server level and only the data that is allowed to be rendered/accessed by the user should be sent to the user’s browser. Rendering might be a bit slower, but less data has to be transmitted (so initial loading might be quicker?).
Generally speaking I thinks forms are a safe way to receive data and have this data directly available in Coda. The processing that happens when the submitted data arrive in the doc is a different story - if you allow records to be merged you do need a unique key that can’t be reverse engineered, like sha256 or Paul’s
I think using the SHA256 function is tricky, because when the original record is changed before the updated data arrive, your SHA256 code in the original record will not be the same as the SHA256 code that will be used in the form. Sooner or later you will run into this issue, since there might pass many days (or months) before the user sends in the form with updated data.
I would love to see couple more options in Coda to tackle these things, but at the same time you have to be careful to use the right tools for the right job. Coda is a document with a lot of data handling possibilities, but it is not a RDMS.
You do realize what you’re asking for here, right?
With this change Coda would have to basically rent a warehouse of servers to do that kind of processing that has been handled by end users’ browsers so far. This ain’t gonna cost $10/month anymore. If they ever do this, I imagine this coming only to the Enterprise tier.
You do realize what you’re asking for here, right?
No, not really. But I do know what I want/need
But I think (some) additional cost would be acceptable for good solutions, al least, for me it is. I am not looking for lowest cost but for most practical in terms of programming and usability.
I hope that, if there is additional cost, it will be included in the team subscription, because I feel that is where it belongs. Or a flat fee small upcharge for docs with these extra features?
Thanks @Paul_Danyliuk , this is the answer I was looking for.
I stay corrected: don’t use row UID as a “secure random key” to amend data.
Reason: the form still leaks all row IDs even with all security settings turned on:
So the constructed SHA1 or something that’s not directly a transformation of a row ID is actually not that bad of an idea.