I'm sure most of us have seen far worse and more nonsensical code, it's a nicely designed snippet to teach basic security issues and show silly mistakes though.
4. It should retrieve one user at a time, rather than all of them.
5. Not understanding basic control flow.
...
There was probably a presentation about this project, where the author received a round of applause. This person was likely promoted for finishing this project in record-time.
The developer that spent time reporting the issue lowered their own performance metrics in exchange for a bug report that was given a low priority. When the developer objected to the prioritization, the project leadership got pissed off and punished the developer evaluation citing reasons such as "does not align with business needs", "has poor communication skills" (talks abstract things that nobody understands or cares about).
By the time this defect was found and fixed, the author likely pushed 10 different other defects just like this. Also, other engineers copied and pasted this code multiple times because it's working and has unit tests.
One bit of awfulness the article missed: Rather than scanning for the username and then checking whether the password is correct, it scans for a match on both username and password. So if you have the right username but the wrong password, it still has to check every single username to conclude this; it won't stop when it gets to the username you entered.
I mean, not that it should be scanning through a list to find the right username, but still...
(And yeah, I suppose that would allow for some sort of username enumeration via a timing attack, but somehow I don't think that's the reason they didn't do that here...)
If you forget a new password, you can create a new one, and then if you remember the old password later, you can use both. Is this so different in principle from supporting multiple methods of authentication? :D
I don't think it matters. With an index on username you don't need to scan. Without an index (like in the example), you have to scan on average half the table for existing names and the full table for missing ones. Adding a check for the password won't affect performance in a way that matters.
The main reason why you can't do this in a correctly written application is that it's incompatible with salted hashes, since you need to get the salt from the database to verify the hash. (You should calculate the hash in the app server, since it's expensive and scaling app servers is usually easier and cheaper than scaling db servers)
Not the worst, though. It maybe insecure because the app was intended for internal use.
I did, however, see some shitty stuff in my job. Like, someone iterates a hashtable to find a key. I didn’t even know what to explain to that person when I reviewed the code.
Hilarious, and a great breakdown of what's wrong with the code!
But also, in an article calling out programming falsehoods, this snippet is a bit odd:
> Even if apiService.sql returns a value synchronously (which I doubt), internally it have to open a connection to a database, make a query and send back the response, which (as you may have guessed) can’t be synchronous.
Sure it can, it's dead simple to write an API that accepts a database query and returns the result synchronously.
But how would you call this API from the browser synchronously? I guess in theory there is a synchronous XHR call but I’ve never seen it used. That could be something you add to the problems.
In the early days of ajax proliferation, I remember reading blog posts where people recommended synchronous XHR to keep your code linear, instead of trying to understand callbacks, which would make the code too complicated.
Well, yeah. You have one thread to work with in the browser, and if you tie it up with a synchronous XHR your application freezes until the request finishes.
Code formatting is indeed minor here compared to the rest, but you missed the one that popped out at me: The opening curly braces are sometimes on the same line as the condition, sometimes on the following line.
That said,
> I’m absolutely sure that the code above is fake.
> That’s the first time that I see a synchronous SQL query:
var accounts = apiService.sql(
"SELECT * FROM users"
);
Edit: Actually hell, it still works, at least in Firefox. It just also logs the deprecation warning mentioned on that page. I thought this was already removed.
You'd have to see all of the code to be sure, but the braces here are on the same line as the statement that opened the scope, except one case where the opening line was split. You don't have to approve, but there may at least be a reason.
Funny I almost commented that you must be mistaken because it would be positively insane to support synchronous requests. Wow, that is insane.
In the end, synchronization can be achieved by busy waiting. So the implementation of apiService.sql() could just rely on that even if the browser API didn't support it.
The code still looks fake to me. Because you have to know quite a bit to create a combination of fails like that. Natural bad code I've seen is less purposefully structured. But maybe I just haven't been exposed to this type.
> In the end, synchronization can be achieved by busy waiting. So the implementation of apiService.sql() could just rely on that even if the browser API didn't support it.
I haven't tested this, but I don't think it can. The result callback doesn't have a chance to run if there's a busy loop - javascript is single-threaded, and callbacks only fire when idle (think cooperative multitasking, not preemptive multitasking).
Webworkers may get around this, but I've not used them and am not sure of the details on how they work. A quick look at a guide indicates they still rely on event callbacks in the main thread, so if my thought above is right, it looks like they wouldn't work either.
It's true! I tested it because I thought it would be possible to just wait for readyState == 4 in a loop. My assumption was that XMLHttpRequest runs in another thread once you do send() on it. And indeed, the request starts immediately. But the instance of XMLHttpRequest doesn't get updated until control is yielded. So you can't get the goods. All considered, that is a good thing :-)
A couple of years ago slack used synchronous requests to fetch the history when scrolling up on the main chat window. Page/browse freezing included. I think it even used a full CPU core spinning instead of blocking on IO.
Hmm. I have hard-coded superusers for an app that are based on email address (where email is the login username). I'd love to hear from the HN experts if that is a very bad idea and how to do it better.
(initially I had a 'superuser' permission that would sort of short-circuit the permission system, but I felt really uncomfortably about how much that affected my code. I figured having compile-time hard-coded superusers per-app-instance would make more sense).
To do it via code, you have to write the code change, run it to make sure you didn't break anything, get the code reviewed, wait for it to compile, and then deploy. In database, you run one simple query.
I think its a bad idea to hard-code anything like that.
If you have to do it then accept it as a command-line argument or read it from a config file - at least then it can be backed-out with an application restart instead of a recompile.
Never did that, but some of my apps that don't require strong security have a line in the configuration file that tells if it's in prod mode or debug mode and if it's in debug mode what user to emulate after a real, successful login. That debug config file is not checked in Git, so it never gets in places I don't want it. This way I do have to login, but I don't mess with test accounts or other people's passwords.
I've seen something like this before that allowed login with any password as long as you gave a valid user name:
> if (hash(password == hashedPassword)) { login(username); }
"Don't write your own hash function" is common advice, but I would go much further and say don't write anything to do with passwords, logins, roles or sessions etc. if you can because one small mistake is all it takes to create a huge security hole.
It really depends what kind of product you are building. Sometimes, especially an enterprise product, monolithic in nature, you have to building user management, session management, role management into the product. It does take a seasoned engineer to do to so. But lot of these concepts are well established. I would say dont write your own hash function, dont create your own concepts in user, role and session management.
Enterprises with a significant number of IT services are well-adviced to think about consolidation of authentication and authentication mechanisms. There is a huge zoo of architectures to choose from (LDAP/AD, Kerberos, OAuth, Radius, OpenID) and most off-the-shelf software has integrations for these. Every password that your users have to remember increases the chance that they use unsafe ones or even write them down on sticky notes on their desktop. Yes, middlewares have bugs too, but most of the trivial ones likely have been found long ago.
Does anyone have any experience with password-less login? Like were you just do the other half of a 2fa like an email? And I mean both experience as a consumer or developer.
I feel like if I were to have a service that required log in that's how I would do it, but with all the talking about it I've never actually seen it in the wild.
I have seen a 'trusted links' concept in production: imagine you have news stories (or similar) behind a paywall. You send out emails to your customers with direct story links that include a token which bypasses the paywall. Optionally, have that link log the user in a low-trust context where step-up auth is required to do e.g. account management.
The best part there is that even the intended code is probably insecure, since == will likely open you to timing attacks and should be replaced with a secure comparison function.
Unless it's also a non-cryptographic hash then I don't see how a timing attack does anything interesting here. Timing will potentially tell you how many bytes of the hash match. But finding a password that produces a hash that matches the first N bytes does not help you find a password that matches the N+1th byte, so you're still just left with a brute force attack.
What am I missing? (Genuinely curious - I'm not a crypto expert)
I disagree. Authentication and authorization are central to many areas in which programmers work. And while there are plenty of gotchas (especially in webdev perhaps), at it's core it can be learned, understood, and implemented right as long as you rely on the experts for the proper tricky bits ("don't roll your own crypto")
Sure, if you can outsource authentication to FB or Apple or OAuth, then that's great. But even then you're still on your own when it comes to authorization. And it's still important to understand what these services are doing for you.
So in the end you still need to properly grok both authentication and authorization.
One of the big 'milestones' in my career was finally building something that involved logins, roles, sessions, etc. It scared the crap out of me from all the HN stuff I'd read. In the end, despite all the gotchas in browser-land in particular, it turned out to not be as complicated as I thought, or at least the complications involved things that no 3rd party service could take care of for me.
Great, but “don’t roll your own auth” should still be the default. I’ve seen far too many awful login systems at any level that I’d really prefer if NO ONE rolled their own, especially no single unsupervised developer.
>... why they’re not hashing passwords inside of their database?
Sending passwords plaintext over the wire isn't good either, even with TLS. You don't want your server to have any knowledge of the plaintext password. For that reason, it's a good idea to salt and hash passwords client-side as well.
An even better idea is to not roll your own authentication if you can help it.
The only threat model this would actually address is a threat from the user himself. Hashing on the client side means the user probably doesn't know his own password. But he still knows how to log in, so the password he accidentally discloses to someone else is trivially convertible to his actual password.
(The threat model has to involve an accident, because if the user wants to know his password, he can just look at it when he logs in.)
The strategy is called "passing the hash", and it will be flagged as a low-priority problem if you get a security review. It doesn't introduce a weakness, but it's a sign that you don't know what you're doing.
(The more classical form is that you _only_ do the hashing on the client side, in which case you've also introduced the issue that your database stores everyone's password in plaintext.)
I doubt this is a serious issue, but it could protect the original password from accidentally being logged on the server, which has happened to respectable organizations.
Connected with password reuse across different websites, this could present a problem for the end user.
> If your server is compromised, you don't want it handling plaintext/raw password input from your users.
This doesn't work; see the other line of the comment you're responding to:
>> if your adversary has broken your TLS then they can also intercept cookies or inject code to capture the plain text
You're assuming that the attacker controls the connection with the user. Such an attacker is free to serve a login page that sends the unhashed password, and read that.
>You're assuming that the attacker controls the connection with the user.
I am making no such assumptions.
>Such an attacker is free to serve a login page that sends the unhashed password, and read that.
Depending on the nature of the server exploit, and depending on if the client code is even delivered via the same server handling requests in the first place. Both are quite large assumption to make.
if your adversary has broken your TLS then they can also intercept cookies or inject code to capture the plain text.
Pretty much this. If you’re stealing a password in transit, you can just steal the auth token instead, and that attack would bypass MFA. If you compromise the server, you’re well past caring about the individual passwords anyway because you can just serve a version of the client code that doesn’t hash on the client side. If you’re phishing the user, it doesn’t matter what the client normally does because the fake login probably isn’t going through your code. If you’re trying to safeguard against CSRF or a related attack, again either the client code got injected or they’re just using your auth token and don’t care about your password
You could salt and hash again on the server side, but its benefits are marginal. But if you don’t salt and hash on the server side, because you did it on the client side, then you have a known vulnerability (“pass the hash”).
>If you compromise the server, you’re well past caring about the individual passwords anyway because you can just serve a version of the client code that doesn’t hash on the client side.
What if the client files are delivered via CDN, and the server in this case is an API?
At the point where I’m on your front end server, I’m not stealing your password, I’m stealing your auth token. I don’t care much about your password once I can harvest auth tokens en masse.
Don’t forget about the main point: hashing and salting on the client side does not replace doing the same thing on the server side.
> Sending passwords plaintext over the wire isn't good either, even with TLS. You don't want your server to have any knowledge of the plaintext password.
This is literally impossible to avoid. Whatever the server receives, that's what the password is.
This is literally untrue. Zero-knowledge comparison protocols exist [1], and their goal is to prevent malicious party from obtaining any knowledge of the secret. Yes, the genuine server will have its copy of the password (or its hash, whatever) and the user will have their copy of the password too. What you don't want is to have the user send their copy of the password to a place which looks like your server but isn't.
EDIT: I mean, yeah, you're right in the sense that whatever you send to the server is used to authenticate you, so that whatever is a 'password' of a sort by definition. However, using the raw password as is for authentication is not a great idea. If you intercept the password, you will be able to compromise any further authentications. There are alternatives that avoid this.
I'm not sure if this is coming down to semantics here but the password is essentially encrypted to everyone except the client, I wouldn't call that sending a password over the wire, you may disagree. This is a unique value for every login attempt.
No, you're right; I wasn't talking about login attempts. I was thinking that PAKE is a way to establish that two parties have common knowledge of a shared secret, and so the password needs to be shared once in order to become a shared secret. But the protocol you link doesn't transfer the password even when setting it.
(Weirdly, the article explicitly notes that s, the salt Carol applies to her own password, is shared with the server and sent over the wire during login. But the salt never appears to be used by the server in any capacity.
And the instruction "Carol must not share x with anybody, and must safely erase it at this step, because it is equivalent to the plaintext password p" doesn't make a lot of sense; presumably Carol isn't going to erase her knowledge of her password -- what does erasing x add?
[The only thing making the password equivalent to x is that the server transmits the value s during the login attempt. If it didn't do that, x would still be useful, but the "password" would be worthless, unless of course s was stored alongside the password...])
True, but if the hashed password is compromised, the user‘s other accounts with the same password might remain safe. So it‘s not about protecting one single account but protecting the user.
Sure, if you've implemented SRP as suggested sidethread, you don't need to send the password over the wire when logging in.
But you're not talking about that. You, rl3, are just misunderstanding what a password is.
If the user types qwe123 to log in, and you hash that in Javascript to 200820e3227815ed1756a6b531e7e0d2, and send 200820e3227815ed1756a6b531e7e0d2 to the server, then the user's plaintext password is 200820e3227815ed1756a6b531e7e0d2.
Right, but you are missing the point. This is a thread about revealing a users "choosen password" to a fake or compromised server. If you aren't going to fully implement SRP like you mentioned, I'd rather a server only see a hash than my actual "chosen password".
I understand the hash becomes the password to that server. That's okay. But each server gets its own hash that's unique. It cant be correlated in dumps or used on our her sites with the same email.
That server can now never know the password my grandma also uses for her email, bank. and every other website across the internet.
> I understand the hash becomes the password to that server. That's okay. But each server gets its own hash that's unique. It cant be correlated in dumps or used on [other] sites with the same email.
First:
> It cant be correlated in dumps
Hashing client-side doesn't help with that. The password already couldn't be correlated in dumps, because it was salted server-side.
> or used on [other] sites with the same email.
This depends on how Mallory obtained the password. It was already hashed and salted server-side.
So consider the example where the user entered a simple password P, the client side hashed P to become C, and the server side rehashed C to become S. C is what went over the wire.
If the server is compromised and the password database is dumped, Mallory gets a bunch of random-looking hashes. She has to crack those. She could do that by enumerating the space of C possibilities -- very long random strings of binary data -- and hashing them once. Or she could do that by enumerating the space of P possibilities -- the things a user types in order to log in -- and hashing them twice.[1]
The first option is essentially impossible. But the second option is easy. (Assuming your grandma used a password that is easy to guess.) Mallory will use the second option. And the password she learns from that approach will transfer perfectly to every other website.
[1] rl3 mentioned salting the user-password client-side. If the user is allowed to log in from multiple machines, then this salt must be stored on the server (so that it can be communicated to the user when the user attempts to log in from a new machine), and will be available to the attacker who's compromised the server.
>Hashing client-side doesn't help with that. The password already couldn't be correlated in dumps, because it was salted server-side.
Yet it does help, because if your server is exploited, the attacker can potentially read the plaintext/cleartext passwords as they're received from the client.
>... and will be available to the attacker who's compromised the server.
Not necessarily. It depends on the nature of the server compromise. Exploit scope is often limited.
>> Hashing client-side doesn't help with that. The password already couldn't be correlated in dumps, because it was salted server-side.
> Yet it does help, because if your server is exploited, the attacker can potentially read the plaintext/cleartext passwords as they're received from the client.
I can't tell if you're agreeing with me and claiming that the client-side hash is valuable for reasons pests didn't mention ("yet it does help"), or disagreeing with me and claiming that the client-side hash is valuable for the reasons pests states. ("yes it does help").
But you have commented elsewhere that you believe pests is correct ( https://news.ycombinator.com/item?id=24027030 ), so I'll note here that reading the password the user typed, straight off a compromised TLS connection, has nothing to do with correlating dumped password hashes. If you can see the user's password, you don't need to learn that password by matching its hash up against the hash of someone else whose password you already know. (And you can't hash the password you read to compare with other hashes stored in the database, because those other hashes are salted.) With the server-side hash already blocking this attack, the client-side hash is adding absolutely nothing.
>With the server-side hash already blocking this attack, the client-side hash is adding absolutely nothing.
We're saying that the protection afforded by server hashing schemes can in some cases be completely bypassed by raw user password input being present on the server when it arrives from the client.
You're saying client-side hashing adds absolutely nothing, on the grounds that all hash function input is known because it is the client, and that it may as well be plaintext at that point.
I disagree that all input is necessarily known, and that the nature of the server exploit as well as client/server architecture, topology, and client hashing scheme all factor in to whether this is the case.
If it is true that client-side hashing is beneficial in some cases, then it is also true that it does not add absolutely nothing. Good security is layered.
Moreover, it in no way obviates the need for server-side hashing, nor TLS.
For all practical purposes, using a zero-knowledge scheme such as SRP is a much better solution, but that still doesn't render client-side hashing completely pointless.
First, decide what you're talking about. Then, say something about it.
You're obviously not talking about correlating hashes in password dumps here. What are you talking about?
> You're saying client-side hashing adds absolutely nothing, on the grounds that all hash function input is known because it is the client, and that it may as well be plaintext at that point.
No, this is just gibberish you made up to put in my mouth.
You have responded in the wrong place. Let's start over.
pests claimed that performing a client-side salt/hash in addition to a server-side salt/hash has two benefits:
P1: User passwords on the server can't be correlated with other passwords in database dumps.
P2: Knowing a user's password on the site so protected will not let you learn the user's password on other, third-party websites.
But claim P1 is nonsense. It is true that user passwords on the server can't be correlated with other passwords in database dumps. But client-side hashing has nothing to do with that. If the client-side hashing were not performed at all, it would still be impossible to correlate user passwords with other passwords in database dumps.
Claim P2 is shaky. It's correct that -- if the method of learning a user's password is to read their active TLS connection with the server -- the password learned by that method will not be useful on other third-party websites. But it does not apply if the attacker's method of learning the user's password was by cracking a password entry in a database dump. The password learned by that method will be whatever the user typed originally, not the hash of it received by the server.
What is the value that you perceive in claims P1 and P2? ("Thanks. That was a really clear and concise explanation.") Why are we describing an entirely spurious claim as "clear"?
>If the client-side hashing were not performed at all, it would still be impossible to correlate user passwords with other passwords in database dumps.
Right—assuming the passwords are gleaned from the database, for example. However, the entire point was that there's no need to do correlation of anything stored server-side in the first place when an attacker is reading the raw user password input as it comes off the wire. Client-side hashing brings this scenario roughly to parity with the protections afforded at the database level.
Database compromise? Server-side salt/hash.
Limited-scope server runtime or network-level compromise? Client-side salt/hash.
Again, it depends on the nature and scope of the exploit.
>But claim P1 is nonsense. It is true that user passwords on the server can't be correlated with other passwords in database dumps. But client-side hashing has nothing to do with that. If the client-side hashing were not performed at all, it would still be impossible to correlate user passwords with other passwords in database dumps.
Not when you're in possession of the user's non-hashed raw password input. That's correlation city, even in the strict literal sense you're talking here.
>It's correct that -- if the method of learning a user's password is to read their active TLS connection with the server -- the password learned by that method will not be useful on other third-party websites.
Then you finally cede that client-side hashing has value.
>Why are we describing an entirely spurious claim as "clear"?
I fail to see how it's spurious when we've established countless times throughout this thread that client-side hashing has value.
Do you think client-side hashing has value? Because your original comments seemed to emphatically deny that.
With server salt version from P -> C -> S a compromised server could just steal C and still salt into S for password verification. Also it's safe on the wire or in any logs, etc.
For the multiple machines comment, that is not true. The server can generate a salt/key (or whatever it should be named in this version) and communicate it over the initial request with the login page which is then sent back along with the altered client password, de-salted/unencrypted/turned into something can be compared to the users password. Basically CSRF. You wouldn't need to store these temp salts either if you embedded a timestamp and sign it.
> For the multiple machines comment, that is not true. The server can generate a salt/key (or whatever it should be named in this version) and communicate it over the initial request with the login page which is then sent back along with the altered client password, de-salted/unencrypted/turned into something can be compared to the users password. Basically CSRF.
I'm not following you. The system described was:
1. The user comes up with P.
2. The website salts and hashes it, creating C = hash(P,salt_c).
3. C is communicated to the server.
4. The server salts and hashes C, creating S = hash(C,salt_s).
Now, in order to log in, the user must send C, not P, to the server. The goal of this design is that the user does not know C. They do know P. So in order to send C, either the user must remember the original value salt_c, or it must be communicated to them so that they can produce C from P.
We are not contemplating the user personally remembering the value of salt_c, but it would be possible to store it in e.g. javascript local storage. But that would prevent the user from logging in from any device that didn't already have the salt stored. If they cleared their browser history and data, it would prevent them from ever logging in again.
So the server must store salt_c. (As noted above, this means it's now perfectly possible for the server to directly verify that P is the user's "password", the value that hashes to C. But the scheme still allows us to avoid sending P over the wire.) Storing salt_c on the server is the only way to allow the user to log in from more than one browser session.
>If the user types qwe123 to log in, and you hash that in Javascript to 200820e3227815ed1756a6b531e7e0d2 ...
By your own words it's already been run through one hash algorithm. Even considering it's being hashed again on the server, that still isn't plaintext.
The plaintext here is qwe123, because that's the raw user input. If it avoids further pedantry, we can agree to call it cleartext if you prefer.
A hash algorithm is not a supernatural function which changes the metaphysical character of data. Whether something is plaintext or ciphertext depends on what you're doing with it.
And to the server in this example, 200820e3227815ed1756a6b531e7e0d2 and qwe123 are exactly equivalent strings. All the server does is run a hash function and record the result. That result is the ciphertext, and the input is the plaintext, no matter how the input was generated.
>A hash algorithm is not a supernatural function which changes the metaphysical character of data.
Again with the condescension.
>And to the server in this example, 200820e3227815ed1756a6b531e7e0d2 and qwe123 are exactly equivalent strings.
Except they're not, because the former is presumed to be salted client-side, and it is not always true that the attackers [who have compromised the server in some manner] will end up knowing that salt.
There are innumerable schemes that can render gaining knowledge of the salt difficult if not impossible, especially in the case of a server exploit that's limited in scope.
>Whatever the server receives, that's what the password is.
I'm not sure what you can do with a "password" that is only valid for a single login and tied to a specific certificate but hey if you want to ride on a technicality I won't stop you. The plain text password that the user types into the input field still remains unknown to the server.
It does not really matters, the purpose of salting is to avoid rainbow table attacks (i.e. comparing against precomputed dictionaries of known hashes).
(Edit: typo)
Ha, this is nothing. We once fired a programmer and had her turn over her code after she failed to turn any work in after a few months. Her code was atrocious and also none of it worked...or even was runnable. The biggest sin was that she wrote all of her code in MS-Word, smart-quotes and all on all the literals. Never once ever tried to run or test any code, just thousands of lines of useless stuff that "looked" like code.
Oh yeah, she's also an adjunct CS professor at a local college.
We had a guy who, after a month of sitting smack-dab in the center of the IT department being busy on his new MacBook, got caught with his pants down because he finally asked for help, and me and a bunch of other devs stood behind him watched in horror as we discovered that not only did he know nothing about programming, he didn't know /any/ keyboard shortcuts.
When we asked him to copy some code from one file to another, he'd click on 'edit' and 'copy', struggle to get to the other file, and then click on 'edit' and 'paste'.
How it went unnoticed is that we were all busy with our own stuff, he was put on some small project that none of us were working on, and we just assumed that nobody would be stupid enough to hire someone without at least /some/ vetting.
He slipped through the cracks because he got hired into another department, and when they found out that he'd worked as a 'developer' at Microsoft they figured he'd be more useful in our department.
In hindsight I feel I should've known something wasn't quite right when every time I walked past his brand-new MacBook, he seemed to /really/ be struggling with something and it never looked like it was code. I imagine he spent the entire month figuring out how to deal with not having a 'start' button.
EDIT: I'll add that while this was in my top 10 of worst situations, there are many others that, for me, provided a convincing argument against the idea that corporations are somehow more efficient or whatever than the government.
My experience with both the public and private sector, beyond a certain size at least, is that they're largely similar in wastefulness/inefficiency/idiocy/etc.
> How it went unnoticed is that we were all busy with our own stuff, he was put on some small project that none of us were working on, and we just assumed that nobody would be stupid enough to hire someone without at least /some/ vetting.
I'm still confused about how this could have happened. Did anybody ever ask how his work was going? Did he just lie and say it was great? Did the person have a manager? Shouldn't the two of them have set some kind of goals and milestones for their first project? Does the company do code review? Wouldn't it be considered odd that the person wasn't sharing any code to be reviewed?
It seems like there must have been some serious culture/management problems at this company.
Back during the dot-com era, we hired someone (and paid for their relocation across the country!) who didn't know how to code. We were a VB6/COM shop at the time and they spent easily 3 days on a simple if..else statement before someone noticed. To their credit, the company was generous with the severance.
There were a couple of reasons why this happened. Firstly because at the time, companies were hiring anyone who could spell "programming". There was this huge shortage of talent. And secondly, everyone was too busy and tired from 14+ hour days to have done a proper interview.
> It seems like there must have been some serious culture/management problems at this company.
Yes. In almost every case I've seen it seems to come down to a localized culture/management issue in the area where the person works. Usually fixed on a particularly terrible senior manager who has the clout and connections to distract from the problem while problem employees fester forever.
> I'm still confused about how this could have happened. Did anybody ever ask how his work was going? Did he just lie and say it was great?
Yes and yes. I suppose he also lied to get his previous job as a 'programmer', or made the whole thing up.
> Did the person have a manager? Shouldn't the two of them have set some kind of goals and milestones for their first project?
He'd been given time to 'get comfortable' and familiar with the codebase, and was left with some really minor tasks. I think management just forgot to check in with him after a week or so, and everyone else around assumed he was busy working on something. Quite a few freelancers in the department who sort of just did their own thing.
> It seems like there must have been some serious culture/management problems at this company.
Maybe. I remember that particular time being really busy because of some big feature that was about to be deployed and, as I mentioned, it was quite common for freelancers to come and go and work on things that didn't really involve the rest of the team.
I think it wasn't really a serious culture/management problem, but more a consequence of the fact that he came from another department after someone discovered that he was a 'programmer', bypassing the usual process.
When I started at this company I got some time to get comfortable too, but I was hired to work on something specific, so the manager in charge of that came up to me pretty soon.
That’s what I felt like when ai joined a company that issued me a macbook for the first time. There’s nothing quite like demonstrating your code to somebody and having the conversation turn into a tutorial on cmd vs ctrl keys. It was probably only a week or two before I had it mostly worked out, but the imposter syndrome was pretty bad for a while. I can imagine falling into the same trap as the fellow in your story if I had trouble with the code too. At some point you start thinking that anything you say will out you so you just shut up and hope to delay the inevitable.
I was okay when I had the proper keyboard in front of me, but I still stumble with reflexively using the correct keys for shortcuts when I'm remote controlling one from the other.
I've found it very difficult to use Ctrl+C to copy from Windows and then Cmd+V to paste on Mac OS without pretty frequently using the wrong modifier key.
Same here. Started a company where employees had Macbooks to work on, and was all kinds of lost for the first few weeks because of it.
Then again, that's still a problem even now, since switching between a PC and Mac on a fairly regular basis still leaves me a tad confused about the shortcuts and key bindings.
Happened to me at the start of the year, I chose macbook because reviews on 16" keyboard said not horrible and the rest of the team where already on it (and I had juniors to support).
I resolved from day one to not fight the machine into behaving like Fedora instead learning the actual shortcuts (and I installed Rectangle).
It took about a week before I was comfortable and a lot of that was remapping my IDE since I have extensive altered keybindings and shortcut keywords for that on linux.
Once I accept it was just a unix with a different DE it wasn't so bad, messes me up more the other way I keep hitting alt+C etc on linux now.
I was in a situation where it went NOTICED for months but the managers were too scared to fire him (a contractor so should have been easy) because there was some 'HR mess-up' that they were very cagey with details on.
Depending on the situation, subcontractors can also be extra hard to fire. If they were hired to fill out staff on a contract, they may be entitled to some kind of workshare percent and threaten breach of contract if you pull their terrible people off work without a replacement. Then they fail to produce a replacement in a timely fashion.
incompetent people can do little snippets of work for a sprint, and then get promoted. and be absolutely unable to deal with anything more complex that a small bit of functionality.
after a couple of sprints, they have the 'chops' to become a manager, or a director, or an engineering VP.
Quite some time ago, I worked in a company that hired a independent contractor for writing some non-trivial code (low level NLP) in C or C++ and interfacing it with a slightly opaque proprietary API. The guy came with an impeccable resume, or so we thought until we found out 6 weeks later that he'd been busy typing garbage, and not a lot of it either. He claimed these 100 to 200 lines were some form of design, but it was so utterly ridiculous that he was sent away immediately. I did have some experience with the API, and ended up with a working module of 2600 lines over a few days.
My favorite was the guy who would come into work, put his jacket on his chair, and then... go to his other full time job. He'd return in the evening to get his stuff and make it look like he'd been working long hours. He got away with it for almost a month.
Someone forgot to give them a programming task at the job interview.
I have met people like this at a job interview (where I gave them a programming task, and the interview ended soon afterwards), and they were charismatic extraverted talkers, with CVs that contained previous software development jobs. I could easily imagine them passing the interview with a non-technical interviewer.
Why wouldn't they? Businesses didn't go through any magical transformation over the last 30 years that would unbreak them. I think it's just a consequence of size: the larger your company is, the less individual contributions matter on the margin, and thus it's easier to coast undetected while not doing anything.
Arguably, the modern obsession with metrics and monitoring is creating even more waste than there was before, as managers invent bullshit metrics, and employees perform fake-work to optimize for them.
It’s not that I expect someone to try and salvage a situation where someone is coding in Word - but is there more to the story when you say this went on for months ? I don’t think I have ever been in an environment where that would ha e been allowed to continue for that long... ? Sounds like an environment scared of dealing with things ?
Could've been and overactive HR situation. Sometimes it's clear that it needs to end, but despite that clarity, the organisation dictates that there be PIP, which then kicks off a documentation period, and so on, which can in fact take months.
Pretty close. It was a perfect storm of her being a subcontractor, buried under a hierarchy of a mix of incompetent subcontractors and incompetent employees who also happened to be fairly senior. In the mix was also a dose of HR sensitive health issues, and subcontractor politics.
In other words it was a mess. And it took a lot of firings to get rid of all of them once the tower of failure was discovered by a new outside hire department head. There appeared to be a something an effect of the incompetent senior person surrounding himself with incompetents who then hired incompetents and turtles all the way down.
It was almost comical that we ended up with such a group of terrible technical staff in this area, but "types code in MS-Word" was definitely the low point and is now a bit of a company legend.
I was on a project where a recently hired Senior Java Developer managed to avoid committing code for three weeks with various excuses. When we finally looked at their code, it was a couple of hundred lines code that looked like Java, but with no semicolons. It didn’t compile.
We had a guy nicknamed jellyfish. He was responsible for crafting a frontend to the university's remote education system in flex and connect it to flash media server. After six months of "coding", he was asked for a demo and all he did was to showcase one of the existing products. After getting fired, he sued the university and got back in to get a few more paychecks before leaving. He was excentric, drawing role playing swords and printing entire books that he never read.
We had a PHP programmer who didn't know the PHP tags (<?php ?>).
He would stare at the screen doing nothing and when every body else was busy and not paying attention to him, he would watch videos and visit gaming websites.
That sounds like several PHP developers I've worked with, who have learned to code in the post-framework era and who have therefore literally never written a vanilla PHP script, or even in some cases used standard library functions.
> Oh yeah, she's also an adjunct CS professor at a local college.
Why is this not surprising at all.
Oh I know, because people think it's "ok" to put CS papers with pseudocode out there.
At this point I'm not sure you can even blame the person if the interview process was so bad that it let a person like that get in.
(Yes please interviewers bore me with another long winded description of FizzBizz or somethng because you don't know how to ask constructive questions that show competency)
Pseudocode is useful for academic papers to demonstrate an idea/algorithm in a condensed form - i.e. Without having to write out many detailed paragraphs.
Although I personally prefer a link to a public repo of code. But I'm a code monkey.
Isn't the whole point of pseudocode that it's a language-agnostic description of an algorithm? Pseudocode written in the 1970s still stands up -- imagine if a COBOL block had been in its place.
> "How do people like this get hired for a programming job in the first place?"
No whiteboarding or coding test during the interview process. As much as I detest them, I wouldn't work for a company that doesn't use them to screen candidates.
I've been developing software professionally for a little over 12 years, and believe myself to be a fairly component. About a year ago I was flown in for an onsight interview for a fairly high level Sr engineer position at upstairs Amazon. During this interview I was handed a blank piece of paper and a pen to implement a fairly trivial programming task. I couldn't even put a couple nested for loops together. I guess over time it just becomes musscle memory. I was totally befuddled even just trying to write a curly brace.
I bet came across to them as totally incompetent fool... "Slipping through the cracks of multiple pre-screening technical interviews before the onsite..."
There are some truly abysmal people in technology. I work in a multidisciplinary environment and deal with not only coders but people from other sci/tech areas and there's also some pretty bizarre, completely incompetent, personalities in other fields as well.
They seem to exist through some kind of combination of manifesting some kind of acute highly-sensitive HR problems (health, special class, etc.), bouncing around from unsuspecting job to job to keep the paychecks coming in, and simply being walking Dunning–Kruger manifestations. Eventually they accumulate enough time in enough jobs that it gets easier and easier to get new jobs due to being experienced and some of them will end up in senior positions where they no longer have to code (or perform in the core of their technical area).
They can come in from all sorts of places, often have stunning educational credentials and backgrounds, often have great looking resumes.
Lol. Reads a little bit like cells accumulating mutations, becoming increasingly unchecked. Cancer analogy would be complete, if they end up training other idiots.
Do companies not have any kind of onboarding process that involves pairing and training? Even if someone knows how to code every project has its own tools and conventions that fresh hires cannot be expected to know. This is really on the company for just leaving her alone for months.
But worse than a real revision control system like git in every way except UI (although I find Word's track-changes and comments interface and presentation to be really clunky and maybe as user hostile as so many say git's CLI UI is)
Agreed about revision control; I wish there was GIT for .docx for situations when you can't use plain text / LaTex.
I do like Word's comments interdace. I wish there was a format for replying to comments in code (aka "comment conversations"), so that IDEs could render them similarly to how Word / Google Docs do.
(I am genuinely looking forward to a vim/emacs user telling me that they have been using such a format for the last 30 years!)
Yes, this is beyond incompetent. Even someone without any programming knowledge would probably know that you can't have an API for checking the username and password combinations of all users.
> Here we can see the use of the double quotes for writing strings ... Here we can see single quotes ... This may not look important, but it’s actually telling us that the developer has probably copied some code from StackOverflow without even rewriting it following a common style guide for the whole codebase.
I have a habit of mixing double and single quotes, depending on what side of bed I woke up on. Doesn't mean I copied my code from Stackoverflow.
I work in a language that only allows double quotes, but I still occasionally type a string with single quotes because that was the accepted style at my last job.
Same. It's very easy to mix them, sometimes on lines entered minutes apart. I'm used to double quotes in C#, C++, Rust, etc. so it's just my natural fallback when coding in Python. I find myself doing it with SQL occasionally too, but there it's quite obvious right after entering the double quote since the string syntax highlighting doesn't kick in.
I don't seem to have a problem with context switching. I use C++ 90% of the time, but in Python I use single quotes just because I'm too lazy to use the Shift key.
When my linter screams at me for not using the correct quotes, I usually think "who cares... it's a string and you know it".
I don't really understand why some languages allow multiple syntax for the same thing.
But it's good to know that in some languages (most shell scripts, Groovy, ...) double-quotes and single-quotes are not exactly the same. String substitution does not exist with single quotes, and I always take far too long to notice that this is why my code is not working.
Does anyone have any experience with password-less login? Like were you just do the other half of a 2fa like an email? And I mean both experience as a consumer or developer.
I feel like if I were to make a service that required log in that's how I would do it, but with all the talking about it I've never actually seen it in the wild.
Firebase offers email login (passwordless) as an auth method. Where you are emailed a new URL that logs you in, each time you wish to.
It also offers SMS based login in a similar manner where no passwords are involved and you just copy a 6 digit or so number from a SMS you receive upon clicking 'Login'
In India this SMS based login method without passwords is the norm for almost all locally developed apps I've used (despite SMS as the sole authentication factor being not really secure due to the possibility of sim swapping, etc).
Disney Plus (Hotstar) in India has recently started mandating users to switch to such SMS based single factor auth (from password based login), presumably to add friction for account sharers.
Do you mean stuff like Medium's 'magic link' approach?
enter email address, get a link via email, click on link: magically logged in!
If so, that's exactly what I've discussed with various clients to implement for their projects, because I agree that in many cases it's a really nice and, as far as I can tell, safe approach.
Personally I really don't like it, because I have a password manager and I rarely have my email open in my browser. But for many, if not most 'casual' computer users it does seem ideal to me.
It feels like a great way to lose users in the login process. They try to log in, go to their email, get distracted by a facebook/whatever login.
Even as a user, it's more friction than a social login or password manager. This is effectively what I needed to do when I used vatsim prior to using a password manager as they made you use a password set by the app that was 8 characters alphanumeric so I used to end up having to reset it a lot.
Monzo Bank here in the UK does that. Your account doesn't have a password. Instead, when you want to log in, it sends you an email with a link that expires after a certain amount of time.
* B2B. The project is targeting companies where everyone relies on email.
* It is easier to implement. Compared to normal email/password-based authentication systems, it is almost exactly like the email verification step but it does not need any "forgot password" or "change password" functionality.
* Access tokens are temporary. If your DB ever gets hacked, the tokens are not valuable in the long run.
* Makes account reusing by multiple people more complicated. This is especially useful when your project uses seat-based pricing.
* Cheap "SSO". You can only use the service as long as you have access to the email address. This might be interesting for companies. People who leave automatically lose access (as soon as the token expires).
Discord is using user/password but every time I want to log in it
says my IP-adress has changed and I have to use my email to
verify my location. So it's basically the same as password-less
email-login.
That's terribly annoying to me as a consumer so please don't do it.
Microsoft uses password-less login across its services (like Outlook, Windows/MS Store, etc). I can still use my password if I absolutely want/have to, but once I enter my email, my Microsoft authenticator app on my phone prompts me for approval. Once I've given it, the site (or app or whatever) lets me in without having to enter the password. I really like it and sort of wish more sites did this.
A colleague of mine once turned in A FULL JAVA APPLICATION all written in the static void main method.
Using booleans in databases polled at 25k/s to check for completion of async tasks.
Worst is, it was working.
I spent 6 months rewriting it, using it as a black blox to recreate the same system, including bugs because we were interfacing with other systems.
Infuriating given that we were a team people team, but also a great deal of fun from the engineering's side.
EDIT: Forgot to mention I was the junior dev and he had in excess of 15 years of experience :D
No, I think he really tried his best, working more than 55 hours / week towards the end. He had been an architect for more than 10 years in a large corp, and joined this small company I joined too.
I think the expectations, lack of coding practice for a few years, architecture jargon that made him seem like an expert was a recipe for disaster. Not completely his fault.
>He had been an architect for more than 10 years in a large corp, and joined this small company I joined too.
A lot of "software architects" are just people that have been at a big corporation long enough that they found someone willing to promote them, but they don't have social skills to put them in a managerial role.
In my experience it often also means they stop coding and only do presentations and (bad) UML Diagrams. Leading to the complete deterioration of their skills.
I have met some architects that were a crucial part of the company. I have also met exactly those that you mention. And arguably they get promoted because they do less harm there than in a team of developers. . .
A company I worked for acquired another company. When we finally got access to their code it was in two files: source.cpp and source2.cpp. The latter was introduced when they reached some limit of the visual c++ compiler at the time.
Right? I suppose he/she is focusing on the naive authentication piece, but I honestly thought most of the code was clean and sensible (the dev is just inexperienced). I’d rather teach this person the technology than someone who constructs labyrinth-like mental models, but knows the technology. They are code terror incarnate.
There are many people that could take that simple function, split it across three files, with various events being dispatched, with “elegant” switch cases, and over abstracted utility functions all over the place. These are the minds I fear, these monsters will eat your sanity with their contraptions.
You know nothing Jon Snow, this code is good. I know what the person was trying to do, and it can mostly be solved. Please purchase a ticket to a few React apps, or a home grown php framework. Then we’ll talk. You have not met a real mind eater yet.
222 comments
[ 2.9 ms ] story [ 263 ms ] threadStill, I agree with one of the posts on reddit, this is a decent ice breaker interview question to see how many problems the candidate can find.
[1] https://www.reddit.com/r/programminghorror/comments/66klvc/t...
2. It should implement this logic server-side.
3. No hashing + salting of passwords.
4. It should retrieve one user at a time, rather than all of them.
5. Not understanding basic control flow.
...
There was probably a presentation about this project, where the author received a round of applause. This person was likely promoted for finishing this project in record-time.
The developer that spent time reporting the issue lowered their own performance metrics in exchange for a bug report that was given a low priority. When the developer objected to the prioritization, the project leadership got pissed off and punished the developer evaluation citing reasons such as "does not align with business needs", "has poor communication skills" (talks abstract things that nobody understands or cares about).
By the time this defect was found and fixed, the author likely pushed 10 different other defects just like this. Also, other engineers copied and pasted this code multiple times because it's working and has unit tests.
I mean, not that it should be scanning through a list to find the right username, but still...
(And yeah, I suppose that would allow for some sort of username enumeration via a timing attack, but somehow I don't think that's the reason they didn't do that here...)
The main reason why you can't do this in a correctly written application is that it's incompatible with salted hashes, since you need to get the salt from the database to verify the hash. (You should calculate the hash in the app server, since it's expensive and scaling app servers is usually easier and cheaper than scaling db servers)
I did, however, see some shitty stuff in my job. Like, someone iterates a hashtable to find a key. I didn’t even know what to explain to that person when I reviewed the code.
But also, in an article calling out programming falsehoods, this snippet is a bit odd:
> Even if apiService.sql returns a value synchronously (which I doubt), internally it have to open a connection to a database, make a query and send back the response, which (as you may have guessed) can’t be synchronous.
Sure it can, it's dead simple to write an API that accepts a database query and returns the result synchronously.
Although I don't recommend doing this it's hardly as difficult as your comment implies.
That said,
> I’m absolutely sure that the code above is fake.
> That’s the first time that I see a synchronous SQL query:
Pretty sure you meant synchronous ajax/web request rather than sql query. This could be old code, because it totally used the be a thing: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequ...Edit: Actually hell, it still works, at least in Firefox. It just also logs the deprecation warning mentioned on that page. I thought this was already removed.
In the end, synchronization can be achieved by busy waiting. So the implementation of apiService.sql() could just rely on that even if the browser API didn't support it.
The code still looks fake to me. Because you have to know quite a bit to create a combination of fails like that. Natural bad code I've seen is less purposefully structured. But maybe I just haven't been exposed to this type.
I haven't tested this, but I don't think it can. The result callback doesn't have a chance to run if there's a busy loop - javascript is single-threaded, and callbacks only fire when idle (think cooperative multitasking, not preemptive multitasking).
Webworkers may get around this, but I've not used them and am not sure of the details on how they work. A quick look at a guide indicates they still rely on event callbacks in the main thread, so if my thought above is right, it looks like they wouldn't work either.
I’ve seen worse code than this. How about a hard coded backdoor check that looked like: || pw == “debug0”
(initially I had a 'superuser' permission that would sort of short-circuit the permission system, but I felt really uncomfortably about how much that affected my code. I figured having compile-time hard-coded superusers per-app-instance would make more sense).
Yes
> and how to do it better.
Put these users/passwords in the database like all the other users so that you can shut them down when the passwords leak to the public.
If you have to do it then accept it as a command-line argument or read it from a config file - at least then it can be backed-out with an application restart instead of a recompile.
> if (hash(password == hashedPassword)) { login(username); }
"Don't write your own hash function" is common advice, but I would go much further and say don't write anything to do with passwords, logins, roles or sessions etc. if you can because one small mistake is all it takes to create a huge security hole.
I feel like if I were to have a service that required log in that's how I would do it, but with all the talking about it I've never actually seen it in the wild.
What am I missing? (Genuinely curious - I'm not a crypto expert)
Sure, if you can outsource authentication to FB or Apple or OAuth, then that's great. But even then you're still on your own when it comes to authorization. And it's still important to understand what these services are doing for you.
So in the end you still need to properly grok both authentication and authorization.
One of the big 'milestones' in my career was finally building something that involved logins, roles, sessions, etc. It scared the crap out of me from all the HN stuff I'd read. In the end, despite all the gotchas in browser-land in particular, it turned out to not be as complicated as I thought, or at least the complications involved things that no 3rd party service could take care of for me.
Probably that's why you were successful. Lots of people make mistakes because they don't understand how important it is.
I really disagree with this. How do you learn about encryption, security et cetera if you don't do it yourself?
It would be like removing the letter B from ABC because the letter B may be unsafe.
I'll take this a step further and say don't push anything important to production that isn't covered by tests.
Sending passwords plaintext over the wire isn't good either, even with TLS. You don't want your server to have any knowledge of the plaintext password. For that reason, it's a good idea to salt and hash passwords client-side as well.
An even better idea is to not roll your own authentication if you can help it.
TLS is quite strong, and if your adversary has broken your TLS then they can also intercept cookies or inject code to capture the plain text.
(The threat model has to involve an accident, because if the user wants to know his password, he can just look at it when he logs in.)
The strategy is called "passing the hash", and it will be flagged as a low-priority problem if you get a security review. It doesn't introduce a weakness, but it's a sign that you don't know what you're doing.
(The more classical form is that you _only_ do the hashing on the client side, in which case you've also introduced the issue that your database stores everyone's password in plaintext.)
Incorrect. Please refer to other comments in reply to you.[0][1]
>It doesn't introduce a weakness, but it's a sign that you don't know what you're doing.
How's the old proverb go? "Those who live in glass houses should not throw stones"
[0] https://news.ycombinator.com/item?id=24026585
[1] https://news.ycombinator.com/item?id=24026954
Connected with password reuse across different websites, this could present a problem for the end user.
If your server is compromised, you don't want it handling plaintext/raw password input from your users.
This doesn't work; see the other line of the comment you're responding to:
>> if your adversary has broken your TLS then they can also intercept cookies or inject code to capture the plain text
You're assuming that the attacker controls the connection with the user. Such an attacker is free to serve a login page that sends the unhashed password, and read that.
I am making no such assumptions.
>Such an attacker is free to serve a login page that sends the unhashed password, and read that.
Depending on the nature of the server exploit, and depending on if the client code is even delivered via the same server handling requests in the first place. Both are quite large assumption to make.
Pretty much this. If you’re stealing a password in transit, you can just steal the auth token instead, and that attack would bypass MFA. If you compromise the server, you’re well past caring about the individual passwords anyway because you can just serve a version of the client code that doesn’t hash on the client side. If you’re phishing the user, it doesn’t matter what the client normally does because the fake login probably isn’t going through your code. If you’re trying to safeguard against CSRF or a related attack, again either the client code got injected or they’re just using your auth token and don’t care about your password
You could salt and hash again on the server side, but its benefits are marginal. But if you don’t salt and hash on the server side, because you did it on the client side, then you have a known vulnerability (“pass the hash”).
What if the client files are delivered via CDN, and the server in this case is an API?
Don’t forget about the main point: hashing and salting on the client side does not replace doing the same thing on the server side.
Per my original, top-level comment:
"For that reason, it's a good idea to salt and hash passwords client-side as well." [emphasis.. nevermind.]
This is literally impossible to avoid. Whatever the server receives, that's what the password is.
[1]: https://www.cossacklabs.com/files/secure-comparator-paper-re...
EDIT: I mean, yeah, you're right in the sense that whatever you send to the server is used to authenticate you, so that whatever is a 'password' of a sort by definition. However, using the raw password as is for authentication is not a great idea. If you intercept the password, you will be able to compromise any further authentications. There are alternatives that avoid this.
For some reason PAKE schemes aren't that commonly used despite having a solid grounding. Matthew Green has a few good articles on them.
As far as I can see, you do need to send the full password over the wire once when you set its value. But the server doesn't need to remember it.
> For some reason PAKE schemes aren't that commonly used despite having a solid grounding.
It doesn't look like something you can implement unilaterally. How's browser support?
(Interestingly, I guess you could implement it unilaterally between your server and client-side javascript...)
Probably the most common scheme is SRP.
https://en.wikipedia.org/wiki/Secure_Remote_Password_protoco...
(Weirdly, the article explicitly notes that s, the salt Carol applies to her own password, is shared with the server and sent over the wire during login. But the salt never appears to be used by the server in any capacity.
And the instruction "Carol must not share x with anybody, and must safely erase it at this step, because it is equivalent to the plaintext password p" doesn't make a lot of sense; presumably Carol isn't going to erase her knowledge of her password -- what does erasing x add?
[The only thing making the password equivalent to x is that the server transmits the value s during the login attempt. If it didn't do that, x would still be useful, but the "password" would be worthless, unless of course s was stored alongside the password...])
Hence why I specified no knowledge of the plaintext password, which is absolutely possible to avoid sending over the wire.
But you're not talking about that. You, rl3, are just misunderstanding what a password is.
If the user types qwe123 to log in, and you hash that in Javascript to 200820e3227815ed1756a6b531e7e0d2, and send 200820e3227815ed1756a6b531e7e0d2 to the server, then the user's plaintext password is 200820e3227815ed1756a6b531e7e0d2.
I understand the hash becomes the password to that server. That's okay. But each server gets its own hash that's unique. It cant be correlated in dumps or used on our her sites with the same email.
That server can now never know the password my grandma also uses for her email, bank. and every other website across the internet.
First:
> It cant be correlated in dumps
Hashing client-side doesn't help with that. The password already couldn't be correlated in dumps, because it was salted server-side.
> or used on [other] sites with the same email.
This depends on how Mallory obtained the password. It was already hashed and salted server-side.
So consider the example where the user entered a simple password P, the client side hashed P to become C, and the server side rehashed C to become S. C is what went over the wire.
If the server is compromised and the password database is dumped, Mallory gets a bunch of random-looking hashes. She has to crack those. She could do that by enumerating the space of C possibilities -- very long random strings of binary data -- and hashing them once. Or she could do that by enumerating the space of P possibilities -- the things a user types in order to log in -- and hashing them twice.[1]
The first option is essentially impossible. But the second option is easy. (Assuming your grandma used a password that is easy to guess.) Mallory will use the second option. And the password she learns from that approach will transfer perfectly to every other website.
[1] rl3 mentioned salting the user-password client-side. If the user is allowed to log in from multiple machines, then this salt must be stored on the server (so that it can be communicated to the user when the user attempts to log in from a new machine), and will be available to the attacker who's compromised the server.
Yet it does help, because if your server is exploited, the attacker can potentially read the plaintext/cleartext passwords as they're received from the client.
>... and will be available to the attacker who's compromised the server.
Not necessarily. It depends on the nature of the server compromise. Exploit scope is often limited.
> Yet it does help, because if your server is exploited, the attacker can potentially read the plaintext/cleartext passwords as they're received from the client.
I can't tell if you're agreeing with me and claiming that the client-side hash is valuable for reasons pests didn't mention ("yet it does help"), or disagreeing with me and claiming that the client-side hash is valuable for the reasons pests states. ("yes it does help").
But you have commented elsewhere that you believe pests is correct ( https://news.ycombinator.com/item?id=24027030 ), so I'll note here that reading the password the user typed, straight off a compromised TLS connection, has nothing to do with correlating dumped password hashes. If you can see the user's password, you don't need to learn that password by matching its hash up against the hash of someone else whose password you already know. (And you can't hash the password you read to compare with other hashes stored in the database, because those other hashes are salted.) With the server-side hash already blocking this attack, the client-side hash is adding absolutely nothing.
We're saying that the protection afforded by server hashing schemes can in some cases be completely bypassed by raw user password input being present on the server when it arrives from the client.
You're saying client-side hashing adds absolutely nothing, on the grounds that all hash function input is known because it is the client, and that it may as well be plaintext at that point.
I disagree that all input is necessarily known, and that the nature of the server exploit as well as client/server architecture, topology, and client hashing scheme all factor in to whether this is the case.
If it is true that client-side hashing is beneficial in some cases, then it is also true that it does not add absolutely nothing. Good security is layered.
Moreover, it in no way obviates the need for server-side hashing, nor TLS.
For all practical purposes, using a zero-knowledge scheme such as SRP is a much better solution, but that still doesn't render client-side hashing completely pointless.
https://crypto.stackexchange.com/questions/25338/why-arent-z...
The first two bullet points in that reply are especially salient to this discussion.
You're obviously not talking about correlating hashes in password dumps here. What are you talking about?
> You're saying client-side hashing adds absolutely nothing, on the grounds that all hash function input is known because it is the client, and that it may as well be plaintext at that point.
No, this is just gibberish you made up to put in my mouth.
The utility of client-side hashing.
>No, this is just gibberish you made up to put in my mouth.
It was actually a good faith attempt to frame your argument.
> The utility of client-side hashing.
You have responded in the wrong place. Let's start over.
pests claimed that performing a client-side salt/hash in addition to a server-side salt/hash has two benefits:
P1: User passwords on the server can't be correlated with other passwords in database dumps.
P2: Knowing a user's password on the site so protected will not let you learn the user's password on other, third-party websites.
But claim P1 is nonsense. It is true that user passwords on the server can't be correlated with other passwords in database dumps. But client-side hashing has nothing to do with that. If the client-side hashing were not performed at all, it would still be impossible to correlate user passwords with other passwords in database dumps.
Claim P2 is shaky. It's correct that -- if the method of learning a user's password is to read their active TLS connection with the server -- the password learned by that method will not be useful on other third-party websites. But it does not apply if the attacker's method of learning the user's password was by cracking a password entry in a database dump. The password learned by that method will be whatever the user typed originally, not the hash of it received by the server.
What is the value that you perceive in claims P1 and P2? ("Thanks. That was a really clear and concise explanation.") Why are we describing an entirely spurious claim as "clear"?
I'd say it was the correct place.
>If the client-side hashing were not performed at all, it would still be impossible to correlate user passwords with other passwords in database dumps.
Right—assuming the passwords are gleaned from the database, for example. However, the entire point was that there's no need to do correlation of anything stored server-side in the first place when an attacker is reading the raw user password input as it comes off the wire. Client-side hashing brings this scenario roughly to parity with the protections afforded at the database level.
Database compromise? Server-side salt/hash.
Limited-scope server runtime or network-level compromise? Client-side salt/hash.
Again, it depends on the nature and scope of the exploit.
>But claim P1 is nonsense. It is true that user passwords on the server can't be correlated with other passwords in database dumps. But client-side hashing has nothing to do with that. If the client-side hashing were not performed at all, it would still be impossible to correlate user passwords with other passwords in database dumps.
Not when you're in possession of the user's non-hashed raw password input. That's correlation city, even in the strict literal sense you're talking here.
>It's correct that -- if the method of learning a user's password is to read their active TLS connection with the server -- the password learned by that method will not be useful on other third-party websites.
Then you finally cede that client-side hashing has value.
>Why are we describing an entirely spurious claim as "clear"?
I fail to see how it's spurious when we've established countless times throughout this thread that client-side hashing has value.
Do you think client-side hashing has value? Because your original comments seemed to emphatically deny that.
For the multiple machines comment, that is not true. The server can generate a salt/key (or whatever it should be named in this version) and communicate it over the initial request with the login page which is then sent back along with the altered client password, de-salted/unencrypted/turned into something can be compared to the users password. Basically CSRF. You wouldn't need to store these temp salts either if you embedded a timestamp and sign it.
I'm not following you. The system described was:
1. The user comes up with P.
2. The website salts and hashes it, creating C = hash(P,salt_c).
3. C is communicated to the server.
4. The server salts and hashes C, creating S = hash(C,salt_s).
Now, in order to log in, the user must send C, not P, to the server. The goal of this design is that the user does not know C. They do know P. So in order to send C, either the user must remember the original value salt_c, or it must be communicated to them so that they can produce C from P.
We are not contemplating the user personally remembering the value of salt_c, but it would be possible to store it in e.g. javascript local storage. But that would prevent the user from logging in from any device that didn't already have the salt stored. If they cleared their browser history and data, it would prevent them from ever logging in again.
So the server must store salt_c. (As noted above, this means it's now perfectly possible for the server to directly verify that P is the user's "password", the value that hashes to C. But the scheme still allows us to avoid sending P over the wire.) Storing salt_c on the server is the only way to allow the user to log in from more than one browser session.
On the contrary. I also suggest sparing the theatrics next time.
>... then the user's plaintext password is 200820e3227815ed1756a6b531e7e0d2.
"In cryptography, plaintext usually means unencrypted information pending input into cryptographic algorithms, usually encryption algorithms." [0]
Or in this case, cryptographic hash functions.
[0] https://en.wikipedia.org/wiki/Plaintext
By your own words it's already been run through one hash algorithm. Even considering it's being hashed again on the server, that still isn't plaintext.
The plaintext here is qwe123, because that's the raw user input. If it avoids further pedantry, we can agree to call it cleartext if you prefer.
And to the server in this example, 200820e3227815ed1756a6b531e7e0d2 and qwe123 are exactly equivalent strings. All the server does is run a hash function and record the result. That result is the ciphertext, and the input is the plaintext, no matter how the input was generated.
Again with the condescension.
>And to the server in this example, 200820e3227815ed1756a6b531e7e0d2 and qwe123 are exactly equivalent strings.
Except they're not, because the former is presumed to be salted client-side, and it is not always true that the attackers [who have compromised the server in some manner] will end up knowing that salt.
There are innumerable schemes that can render gaining knowledge of the salt difficult if not impossible, especially in the case of a server exploit that's limited in scope.
>Whatever the server receives, that's what the password is.
I'm not sure what you can do with a "password" that is only valid for a single login and tied to a specific certificate but hey if you want to ride on a technicality I won't stop you. The plain text password that the user types into the input field still remains unknown to the server.
https://en.wikipedia.org/wiki/Salted_Challenge_Response_Auth...
Oh yeah, she's also an adjunct CS professor at a local college.
How did that go un-noticed for months?
When we asked him to copy some code from one file to another, he'd click on 'edit' and 'copy', struggle to get to the other file, and then click on 'edit' and 'paste'.
How it went unnoticed is that we were all busy with our own stuff, he was put on some small project that none of us were working on, and we just assumed that nobody would be stupid enough to hire someone without at least /some/ vetting.
He slipped through the cracks because he got hired into another department, and when they found out that he'd worked as a 'developer' at Microsoft they figured he'd be more useful in our department.
In hindsight I feel I should've known something wasn't quite right when every time I walked past his brand-new MacBook, he seemed to /really/ be struggling with something and it never looked like it was code. I imagine he spent the entire month figuring out how to deal with not having a 'start' button.
EDIT: I'll add that while this was in my top 10 of worst situations, there are many others that, for me, provided a convincing argument against the idea that corporations are somehow more efficient or whatever than the government.
My experience with both the public and private sector, beyond a certain size at least, is that they're largely similar in wastefulness/inefficiency/idiocy/etc.
I'm still confused about how this could have happened. Did anybody ever ask how his work was going? Did he just lie and say it was great? Did the person have a manager? Shouldn't the two of them have set some kind of goals and milestones for their first project? Does the company do code review? Wouldn't it be considered odd that the person wasn't sharing any code to be reviewed?
It seems like there must have been some serious culture/management problems at this company.
There were a couple of reasons why this happened. Firstly because at the time, companies were hiring anyone who could spell "programming". There was this huge shortage of talent. And secondly, everyone was too busy and tired from 14+ hour days to have done a proper interview.
Yes. In almost every case I've seen it seems to come down to a localized culture/management issue in the area where the person works. Usually fixed on a particularly terrible senior manager who has the clout and connections to distract from the problem while problem employees fester forever.
Yes and yes. I suppose he also lied to get his previous job as a 'programmer', or made the whole thing up.
> Did the person have a manager? Shouldn't the two of them have set some kind of goals and milestones for their first project?
He'd been given time to 'get comfortable' and familiar with the codebase, and was left with some really minor tasks. I think management just forgot to check in with him after a week or so, and everyone else around assumed he was busy working on something. Quite a few freelancers in the department who sort of just did their own thing.
> It seems like there must have been some serious culture/management problems at this company.
Maybe. I remember that particular time being really busy because of some big feature that was about to be deployed and, as I mentioned, it was quite common for freelancers to come and go and work on things that didn't really involve the rest of the team.
I think it wasn't really a serious culture/management problem, but more a consequence of the fact that he came from another department after someone discovered that he was a 'programmer', bypassing the usual process.
When I started at this company I got some time to get comfortable too, but I was hired to work on something specific, so the manager in charge of that came up to me pretty soon.
having different keymappings in different machines is hard
I've found it very difficult to use Ctrl+C to copy from Windows and then Cmd+V to paste on Mac OS without pretty frequently using the wrong modifier key.
Then again, that's still a problem even now, since switching between a PC and Mac on a fairly regular basis still leaves me a tad confused about the shortcuts and key bindings.
I resolved from day one to not fight the machine into behaving like Fedora instead learning the actual shortcuts (and I installed Rectangle).
It took about a week before I was comfortable and a lot of that was remapping my IDE since I have extensive altered keybindings and shortcut keywords for that on linux.
Once I accept it was just a unix with a different DE it wasn't so bad, messes me up more the other way I keep hitting alt+C etc on linux now.
allow me a counter.
incompetent people can do little snippets of work for a sprint, and then get promoted. and be absolutely unable to deal with anything more complex that a small bit of functionality. after a couple of sprints, they have the 'chops' to become a manager, or a director, or an engineering VP.
Quite some time ago, I worked in a company that hired a independent contractor for writing some non-trivial code (low level NLP) in C or C++ and interfacing it with a slightly opaque proprietary API. The guy came with an impeccable resume, or so we thought until we found out 6 weeks later that he'd been busy typing garbage, and not a lot of it either. He claimed these 100 to 200 lines were some form of design, but it was so utterly ridiculous that he was sent away immediately. I did have some experience with the API, and ended up with a working module of 2600 lines over a few days.
I have met people like this at a job interview (where I gave them a programming task, and the interview ended soon afterwards), and they were charismatic extraverted talkers, with CVs that contained previous software development jobs. I could easily imagine them passing the interview with a non-technical interviewer.
Arguably, the modern obsession with metrics and monitoring is creating even more waste than there was before, as managers invent bullshit metrics, and employees perform fake-work to optimize for them.
It’s not that I expect someone to try and salvage a situation where someone is coding in Word - but is there more to the story when you say this went on for months ? I don’t think I have ever been in an environment where that would ha e been allowed to continue for that long... ? Sounds like an environment scared of dealing with things ?
In other words it was a mess. And it took a lot of firings to get rid of all of them once the tower of failure was discovered by a new outside hire department head. There appeared to be a something an effect of the incompetent senior person surrounding himself with incompetents who then hired incompetents and turtles all the way down.
It was almost comical that we ended up with such a group of terrible technical staff in this area, but "types code in MS-Word" was definitely the low point and is now a bit of a company legend.
https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-s...
https://thedailywtf.com/articles/The_Brillant_Paula_Bean
It's a shame the lengths universities will go just to make sure they look good, even if that includes rehiring problematic employees.
He would stare at the screen doing nothing and when every body else was busy and not paying attention to him, he would watch videos and visit gaming websites.
He was supposed to be a web developer but honestly I don't know how we passed his classes. He didn't know anything.
And, of course, we didn't hire him after the 3 months period ended.
Why is this not surprising at all.
Oh I know, because people think it's "ok" to put CS papers with pseudocode out there.
At this point I'm not sure you can even blame the person if the interview process was so bad that it let a person like that get in.
(Yes please interviewers bore me with another long winded description of FizzBizz or somethng because you don't know how to ask constructive questions that show competency)
With real code, those problems are less likely.
Although I personally prefer a link to a public repo of code. But I'm a code monkey.
But today it's more of a crutch than anything else, when you can have actual code running.
No whiteboarding or coding test during the interview process. As much as I detest them, I wouldn't work for a company that doesn't use them to screen candidates.
I bet came across to them as totally incompetent fool... "Slipping through the cracks of multiple pre-screening technical interviews before the onsite..."
Maybe I should bookmark this thread? This and the other examples in this thread is so crazy it should make me feel super productive any day ;-)
They seem to exist through some kind of combination of manifesting some kind of acute highly-sensitive HR problems (health, special class, etc.), bouncing around from unsuspecting job to job to keep the paychecks coming in, and simply being walking Dunning–Kruger manifestations. Eventually they accumulate enough time in enough jobs that it gets easier and easier to get new jobs due to being experienced and some of them will end up in senior positions where they no longer have to code (or perform in the core of their technical area).
They can come in from all sorts of places, often have stunning educational credentials and backgrounds, often have great looking resumes.
I do like Word's comments interdace. I wish there was a format for replying to comments in code (aka "comment conversations"), so that IDEs could render them similarly to how Word / Google Docs do.
(I am genuinely looking forward to a vim/emacs user telling me that they have been using such a format for the last 30 years!)
They could write fizzbuzz tho.
The expectation of junior developers seems pretty low. I think I've been job seeking below my mark...
I have a habit of mixing double and single quotes, depending on what side of bed I woke up on. Doesn't mean I copied my code from Stackoverflow.
I don't really understand why some languages allow multiple syntax for the same thing.
But it's good to know that in some languages (most shell scripts, Groovy, ...) double-quotes and single-quotes are not exactly the same. String substitution does not exist with single quotes, and I always take far too long to notice that this is why my code is not working.
I feel like if I were to make a service that required log in that's how I would do it, but with all the talking about it I've never actually seen it in the wild.
It also offers SMS based login in a similar manner where no passwords are involved and you just copy a 6 digit or so number from a SMS you receive upon clicking 'Login'
In India this SMS based login method without passwords is the norm for almost all locally developed apps I've used (despite SMS as the sole authentication factor being not really secure due to the possibility of sim swapping, etc).
Disney Plus (Hotstar) in India has recently started mandating users to switch to such SMS based single factor auth (from password based login), presumably to add friction for account sharers.
enter email address, get a link via email, click on link: magically logged in!
If so, that's exactly what I've discussed with various clients to implement for their projects, because I agree that in many cases it's a really nice and, as far as I can tell, safe approach.
Personally I really don't like it, because I have a password manager and I rarely have my email open in my browser. But for many, if not most 'casual' computer users it does seem ideal to me.
Even as a user, it's more friction than a social login or password manager. This is effectively what I needed to do when I used vatsim prior to using a password manager as they made you use a password set by the app that was 8 characters alphanumeric so I used to end up having to reset it a lot.
* B2B. The project is targeting companies where everyone relies on email.
* It is easier to implement. Compared to normal email/password-based authentication systems, it is almost exactly like the email verification step but it does not need any "forgot password" or "change password" functionality.
* Access tokens are temporary. If your DB ever gets hacked, the tokens are not valuable in the long run.
* Makes account reusing by multiple people more complicated. This is especially useful when your project uses seat-based pricing.
* Cheap "SSO". You can only use the service as long as you have access to the email address. This might be interesting for companies. People who leave automatically lose access (as soon as the token expires).
That's terribly annoying to me as a consumer so please don't do it.
Infuriating given that we were a team people team, but also a great deal of fun from the engineering's side.
EDIT: Forgot to mention I was the junior dev and he had in excess of 15 years of experience :D
From your description, it looks like the code was optimized to irritate while remaining functional.
Might he have been pissed with the institution he worked for?
I think the expectations, lack of coding practice for a few years, architecture jargon that made him seem like an expert was a recipe for disaster. Not completely his fault.
A lot of "software architects" are just people that have been at a big corporation long enough that they found someone willing to promote them, but they don't have social skills to put them in a managerial role.
In my experience it often also means they stop coding and only do presentations and (bad) UML Diagrams. Leading to the complete deterioration of their skills.
I have met some architects that were a crucial part of the company. I have also met exactly those that you mention. And arguably they get promoted because they do less harm there than in a team of developers. . .
You wasted valuable resourcss rewriting a working product? Good job.. I guess.
Especially around:
There are many people that could take that simple function, split it across three files, with various events being dispatched, with “elegant” switch cases, and over abstracted utility functions all over the place. These are the minds I fear, these monsters will eat your sanity with their contraptions.
You know nothing Jon Snow, this code is good. I know what the person was trying to do, and it can mostly be solved. Please purchase a ticket to a few React apps, or a home grown php framework. Then we’ll talk. You have not met a real mind eater yet.