Wes Day



  • There's a super secret admin page deployed to a bunch of sites my company manages. You need a password to access it. The password is only available on an internal webpage, and it changes automatically and periodically. The password is generated "securely" and "randomly" using custom algorithm.

    There's some other changes that need to be done on the generator page, so I'm tasked with updating it from classic asp to .Net, giving it a bit of a face lift, etc. That means re-implementing the algorithm.

    I'd kinda brushed up against this algorithm in the past. I'm sure between the airquotes above, the fact that it has to be syncronized, and the fact that I'm posting it here-- the algorithm is hardcoded absurdest shit. Obviously. It's pretty much take part of the day name, part of the month name, AM or PM, reverse and lower case, mash in some squiggles and brackets (in fixed places, not at random), and bam, password.

    Admittedly, it'll survive a brute force attack, and it works well enough. It isn't so much the concept, it was the implementation. Jesus shit, it's like the original developer knew not enough of everything.

    Ask classic ASP for the month name or the day number? NO! Make an SQL query to select it by casting getdate() into a varchar and substringing it.

    Use built-in libraries or functions to get the day name? NO! Take the day number and hard-code the abbreviation in a select case statement.

    It takes me a few hours to unravel that all and remove the SQL statement. It still doesn't take timezones into account-- but since all the sites this is installed on are in the same timezone, it's a bug I'm willing to accept.

    New page works fine. Password being generated is fine. Done. Except for two days ago (I'm writing this Friday, since it took that long to sober up) I get the bug report that it isn't working all of a sudden.

    Debug debug debug-- and I drill it down to the fact that the password my page generates is (slightly redacted) yam}dew-- because it's a [b]WED[/b]nesday in [b]MAY[/b]. But the password expected, and that the old page generates-- is yam}sew

    Look at the code, and sure enough:


     

          Select Case
    datepart("w",date())

             Case "1"     todaypwdAsp = LCase("NUS" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "2"     todaypwdAsp = LCase("NOM" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "3"     todaypwdAsp = LCase("EUT" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "4"     todaypwdAsp = LCase("SEW" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "5"     todaypwdAsp = LCase("UHT" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "6"     todaypwdAsp = LCase("IRF" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "7"     todaypwdAsp = LCase("TAS" & StrReverse(right(formatdatetime(time(),3),2)))

          End Select

     

    Do you see it? DO YOU SEE IT?

    And since the same code is rolled out to dozens of clients, I had to reproduce the bug in my port of the algorithm. 😞

    The original developer had to do things the hard way because they didn't understand how to handle date/time, and even then they did THAT wrong. So just remember next time you have to fix a bug by making your code just as bad as the original failure of a human being, you can rest assured that you aren't the only one out there having a Wes Day.

     



  • @Lorne Kates said:

    Ask classic ASP for the month name or the day number? NO! Make an SQL query to select it by casting getdate() into a varchar and substringing it.

    This is called defensive 3-tier programming. It prevents problems caused by a potential discrepancy between the clocks of the web and database servers.



  • @Ronald said:

    @Lorne Kates said:

    Ask classic ASP for the month name or the day number? NO! Make an SQL query to select it by casting getdate() into a varchar and substringing it.

    This is called defensive 3-tier programming. It prevents problems caused by a potential discrepancy between the clocks of the web and database servers.

    I don't think the database server needs to be involved in this at all.  From what I gather, the password is generated and used only in the website.



  •  @Sutherlands said:

    @Ronald said:
    @Lorne Kates said:

    Ask classic ASP for the month name or the day number? NO! Make an SQL query to select it by casting getdate() into a varchar and substringing it.

    This is called defensive 3-tier programming. It prevents problems caused by a potential discrepancy between the clocks of the web and database servers.

    I don't think the database server needs to be involved in this at all.  From what I gather, the password is generated and used only in the website.

    Not to mention that if you have clock skew bad enough to make the day and/or the month wrong between multiple computers in the same timezone, then you've got some much bigger issues.

     



  • @DescentJS said:

     @Sutherlands said:

    @Ronald said:
    @Lorne Kates said:

    Ask classic ASP for the month name or the day number? NO! Make an SQL query to select it by casting getdate() into a varchar and substringing it.

    This is called defensive 3-tier programming. It prevents problems caused by a potential discrepancy between the clocks of the web and database servers.

    I don't think the database server needs to be involved in this at all.  From what I gather, the password is generated and used only in the website.

    Not to mention that if you have clock skew bad enough to make the day and/or the month wrong between multiple computers in the same timezone, then you've got some much bigger issues.

    How come nobody gets jokes?



  • @DescentJS said:

    if you have clock skew bad enough to make the day and/or the month wrong between multiple computers in the same timezone, then you've got some much bigger issues.

     

    Joke aside, let's revisit this comment on Dec 31 at 23:59:59



  • We had a developer misspell "Febuary" and not notice it until showing the page to the client. It was kind of embarrassing.



  • @Lorne Kates said:

    There's a super secret admin page deployed to a bunch of sites my company manages. You need a password to access it. The password is only available on an internal webpage, and it changes automatically and periodically. The password is generated "securely" and "randomly" using custom algorithm.

     

    I once inherited a codebase semi-similar to this one (fixed password generation).
    I had to change it pretty quick- a peek at the logs revealed that someone had actually written a bot to crawl these particular admin pages, and do a weekly rip of the databases from each and every one.

     



  • @blakeyrat said:

    We had a developer misspell "Febuary" and not notice it until showing the page to the client. It was kind of embarrassing.

    My favorite has to be "priviledge". Can't tell you how many times I've seen that in production code and UIs..



  • @SamC said:

    I once inherited a codebase semi-similar to this one (fixed password generation).

    How the fuck hard is it for people to learn HMAC? And, really, you should just be using one of those third-party auth token services.



  • @morbiuswilters said:

    @blakeyrat said:
    We had a developer misspell "Febuary" and not notice it until showing the page to the client. It was kind of embarrassing.

    My favorite has to be "priviledge". Can't tell you how many times I've seen that in production code and UIs..

    Ha! I was working the computer desk at a New England college many years ago. Helped a guy who could not figure out why the Fortran compiler didn't like his INTERGER NFOO declaration. Good thing that one of us had grown up in the Midwest. 🙂



  • @D-Coder said:

    @morbiuswilters said:

    @blakeyrat said:
    We had a developer misspell "Febuary" and not notice it until showing the page to the client. It was kind of embarrassing.

    My favorite has to be "priviledge". Can't tell you how many times I've seen that in production code and UIs..

    Ha! I was working the computer desk at a New England college many years ago. Helped a guy who could not figure out why the Fortran compiler didn't like his INTERGER NFOO declaration. Good thing that one of us had grown up in the Midwest. 🙂

    I have a friend who pronounces it IN TEEG JER



  • @morbiuswilters said:

    @blakeyrat said:
    We had a developer misspell "Febuary" and not notice it until showing the page to the client. It was kind of embarrassing.

    My favorite has to be "priviledge". Can't tell you how many times I've seen that in production code and UIs..

    When I was at the USGS, I worked with an API that had "OnFileNameChoosen"



  • It's not a spelling error, per se, but I can never remember whether things in JavaScript are onchange or onchanged.



  • @morbiuswilters said:

    How the fuck hard is it for people to learn HMAC?
     

    How the fuck hard is it for people to learn to spell Wednesday?

    How the fuck hard is it to learn HMAC relative to being able to spell Wednesday?

     



  • @Ben L. said:

    It's not a spelling error, per se, but I can never remember whether things in JavaScript are onchange or onchanged.

    I think they're all present-tense: onchange, onload, onbeforeunload..



  • @D-Coder said:

    @morbiuswilters said:

    @blakeyrat said:
    We had a developer misspell "Febuary" and not notice it until showing the page to the client. It was kind of embarrassing.

    My favorite has to be "priviledge". Can't tell you how many times I've seen that in production code and UIs..

    Ha! I was working the computer desk at a New England college many years ago. Helped a guy who could not figure out why the Fortran compiler didn't like his INTERGER NFOO declaration. Good thing that one of us had grown up in the Midwest. 🙂

    In New England I'd expect "Intehgeh".



  • @Lorne Kates said:

    @morbiuswilters said:

    How the fuck hard is it for people to learn HMAC?
     

    How the fuck hard is it for people to learn to spell Wednesday?

    How the fuck hard is it to learn HMAC relative to being able to spell Wednesday?

     

    Misspelling something is pretty bad, but I'd take a guy who can't spell but understands high-level concepts over the state spelling bee champ who insists on using Go.



  • I freely admit to requesting a change to a database to fix the "misspelled" column "amount" to "ammount".



  • @MiffTheFox said:

    I freely admit to requesting a change to a database to fix the "misspelled" column "amount" to "ammount".

    My favorite is the HTTP spec.. "referer". I shudder every time I type it. The fact that that made it through the glacial standards process should tell you everything you need to know about how well standards bodies work.


    If it doesn't, I call Exhibit B "XHTML2".



  • @morbiuswilters said:

    @D-Coder said:
    Ha! I was working the computer desk at a New England college many years ago. Helped a guy who could not figure out why the Fortran compiler didn't like his INTERGER NFOO declaration. Good thing that one of us had grown up in the Midwest. 🙂

    In New England I'd expect "Intehgeh".

    Elsewhere, I've heard "in-TEE-grrr".

     


  • Discourse touched me in a no-no place

    @morbiuswilters said:

    "referer"
    Please consider my teeth to be duly ground.



  • Eh. English spelling reform has to start somewhere.

    HTTP/1.1 200 OK
    Kantent-Typ: text/html; charset=utf-8
    Survur: Mykrosaft-IIS/8.0
    X-Paour'd-By: ASP.NET
    Daet: Sat, 25 Mae 2013 15:07:42 GMT
    Kunektun: klos
    Kantent-Laength: 1908
    


  • @MiffTheFox said:

    Eh. English spelling reform has to start somewhere.

    HTTP/1.1 200 OK
    Kantent-Typ: text/html; charset=utf-8
    Survur: Mykrosaft-IIS/8.0
    X-Paour'd-By: ASP.NET
    Daet: Sat, 25 Mae 2013 15:07:42 GMT
    Kunektun: klos
    Kantent-Laength: 1908
    

    Nice.



  • @Lorne Kates said:

    Debug debug debug-- and I drill it down to the fact that the password my page generates is (slightly redacted) yam}dew-- because it's a WEDnesday in MAY. But the password expected, and that the old page generates-- is yam}sew

    Look at the code, and sure enough:


     

          Select Case
    datepart("w",date())

             Case "1"     todaypwdAsp = LCase("NUS" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "2"     todaypwdAsp = LCase("NOM" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "3"     todaypwdAsp = LCase("EUT" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "4"     todaypwdAsp = LCase("SEW" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "5"     todaypwdAsp = LCase("UHT" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "6"     todaypwdAsp = LCase("IRF" & StrReverse(right(formatdatetime(time(),3),2)))

             Case "7"     todaypwdAsp = LCase("TAS" & StrReverse(right(formatdatetime(time(),3),2)))

          End Select

     

    Do you see it? DO YOU SEE IT?

    Is it the way you calculate something in two separate places that have to match perfectly, rather than calculating it just once and using the result twice?




  • @Lorne Kates said:

    Use built-in libraries or functions to get the day name? NO! Take the day number and hard-code the abbreviation in a select case statement.

    I might have done something like this, to avoid problems when someone changes the system language. "Wesday" is one thing, and "Mercredi" is another. (This sort of thing is probably more important if, like me, you live in a country whose national language is not English.)

    I say "might", because of course the sane way to work is to use the built-in libraries and explicitly request the conversion to English rather than rely on system defaults.



  • @Snowyowl said:

    I say "might", because of course the sane way to work is to use the built-in libraries and explicitly request the conversion to English rather than rely on system defaults.
     

    That's what I did when I re-implemented in .Net, given that some of the servers are running on French Catholic school boards, and they goddamn insist on French everyFUCKINGthing.

    But keep in mind that just two weeks ago I "solved" a problem that they couldn't solve for, literally, a decade. If they tried to put a string date into the database, it would fail-- because this would fail:

    strSQL = "UPDATE tblStupidTable SET dt_col_UpdateDate='" & txtDay.Text & "/" & txtMonth.Text  & "/" & txtYear.Text & "'" 

    Because ca-EN uses dd/mm/yyyy, and ca-FR uses mm/dd/yyyy. The existing solution was to rewrite every page that got implemented on a French school board to invert txtDay and txtMonth.

    Y'know-- instead of just doing String.Format("{0}-{1}-{2}", txtYear.Text, txtMonth.Text, txtDay.Text) // ISO8601 Motherfuckers!

    (Or, God forbid-- construct an actual data/time object and pass it as a parameter... HIGH CONCEPT!)



  • @Snowyowl said:

    I say "might", because of course the sane way to work is to use the built-in libraries and explicitly request the conversion to English rather than rely on system defaults.

    Or use unambiguous numbers. Or better yet, don't generate predictable "random" passwords.



  • @morbiuswilters said:

    @Snowyowl said:
    I say "might", because of course the sane way to work is to use the built-in libraries and explicitly request the conversion to English rather than rely on system defaults.

    Or use unambiguous numbers. Or better yet, don't generate predictable "random" passwords on a schedule.

    TRWTFTFY



  • @Ben L. said:

    @morbiuswilters said:
    @Snowyowl said:
    I say "might", because of course the sane way to work is to use the built-in libraries and explicitly request the conversion to English rather than rely on system defaults.

    Or use unambiguous numbers. Or better yet, don't generate predictable "random" passwords on a schedule.

    TRWTFTFY

    What? That's a pretty standard way to handle authentication between two systems that don't have any other way to securely communicate. Have you never seen those RSA tokens?



  • @Lorne Kates said:

             Case "4"     todaypwdAsp = LCase("SEW" &

    Do you see it? DO YOU SEE IT?

     

    Took me a long time to see it ("SEW"  should be "DEW", the first three characters of "WEDNESDAY, backwards).

    But the first thing I noticed is that he has multiple calls to time(). He only makes one of the calls, but he must have other calls for the month name, day of the month, etc. Sure it works every afternoon, but what happens when midnight occurs between two of the calls? You should "never" call time() more than once.

    Then I remembered that this is just to generate a random password. WTF! Why doesn't he just call rand(time()) and be done with it? It's just a copy-and-paste random string, right?

     

     



  • @AndyCanfield said:

    @Lorne Kates said:

             Case "4"     todaypwdAsp = LCase("SEW" &

    Do you see it? DO YOU SEE IT?

     

    Took me a long time to see it ("SEW"  should be "DEW", the first three characters of "WEDNESDAY, backwards).

    But the first thing I noticed is that he has multiple calls to time(). He only makes one of the calls, but he must have other calls for the month name, day of the month, etc. Sure it works every afternoon, but what happens when midnight occurs between two of the calls? You should "never" call time() more than once.

    Then I remembered that this is just to generate a random password. WTF! Why doesn't he just call rand(time()) and be done with it? It's just a copy-and-paste random string, right?

     

     

    What if midnight happens between the password being generated and the password being validated?



  • @Ben L. said:

    What if midnight happens between the password being generated and the password being validated?

    You build in a grace period.



  • @morbiuswilters said:

    @Ben L. said:
    What if midnight happens between the password being generated and the password being validated?

    You build in a grace period.

    Like this?

    package main
    
    import (
    	"crypto/sha1"
    	"encoding/base64"
    	"net/http"
    	"time"
    )
    
    const nonceFormat = "2006-01-02-PM"
    
    func GetNonce(w http.ResponseWriter, r *http.Request, key string) string {
    	t := time.Now().UTC()
    	hash := sha1.New()
    	hash.Write([]byte(t.Format(nonceFormat)))
    	hash.Write([]byte(key))
    	// TODO: make this user-specific
    	return base64.StdEncoding.EncodeToString(hash.Sum(nil))
    }
    
    func CheckNonce(w http.ResponseWriter, r *http.Request, key string) bool {
    	nonce := r.PostFormValue("nonce")
    	if nonce == "" {
    		http.Error(w, "invalid nonce", http.StatusBadRequest)
    		return true
    	}
    
    	t := time.Now().UTC()
    	hash := sha1.New()
    	hash.Write([]byte(t.Format(nonceFormat)))
    	hash.Write([]byte(key))
    	// TODO: make this user-specific
    	if base64.StdEncoding.EncodeToString(hash.Sum(nil)) == nonce {
    		return false
    	}
    
    	t = t.Add(-12 * time.Hour)
    	hash.Reset()
    	hash.Write([]byte(t.Format(nonceFormat)))
    	hash.Write([]byte(key))
    	// TODO: make this user-specific
    	if base64.StdEncoding.EncodeToString(hash.Sum(nil)) == nonce {
    		return false
    	}
    
    	http.Error(w, "invalid nonce", http.StatusBadRequest)
    	return true
    }
    


  • @morbiuswilters said:

    @Ben L. said:
    What if midnight happens between the password being generated and the password being validated?

    You build in a grace period.

    Even better: you document this as an unsupported edge case scenario and you move on to work on something that matters.



  • @Ronald said:

    @morbiuswilters said:
    @Ben L. said:
    What if midnight happens between the password being generated and the password being validated?

    You build in a grace period.

    Even better: you document this as an unsupported edge case scenario and you move on to work on something that matters.

    "I edited a document during my lunch break and when I submitted it it said that I was a hacker"

    CLOSED WONTFIX



  • @Ben L. said:

    Like this?

    Why does your CheckNonce function return true for an invalid nonce and false for a valid one?

    Other than that, yeah, that seems to satisfy the basic algorithm. I'd probably code it a bit differently, depending on requirements.



  • @Ronald said:

    @morbiuswilters said:
    @Ben L. said:
    What if midnight happens between the password being generated and the password being validated?

    You build in a grace period.

    Even better: you document this as an unsupported edge case scenario and you move on to work on something that matters.

    It's really easy to build in a grace period, and it saves users a lot of hassle for when they generate a temporary password that expires immediately.



  • @morbiuswilters said:

    My favorite is the HTTP spec.. "referer". I shudder every time I type it. The fact that that made it through the glacial standards process should tell you everything you need to know about how well standards bodies work.
     

    It's the same thing as what happened on Wes Day - the word was misspelled in the FTP spec as well, so HTTP followed suit. Presumably the suggestion that mistakes of the past not be repeated was CLOSED WONTFIX.

    Now, okay: I get that if you outsource to programmers for whom English is a foreign language they might not realise that "Physcometric" is wrong - that might even get past English speakers without proofreading. But this software I've got here didn't get proofread. So it went out live saying "physcometric". And "permistion", and "brithday" and "firt name". In the UI, in the codebase, in the wire protocol, in the db schema.... Except of course when it doesn't.

     



  • Even Microsoft isn't immune - Slovenian translation of Office 2010 installer had two letters transposed under the progress bar (which was really hard to miss), and in Windows 7 shutdown menu one entry had (well, has - those things don't get fixed once the product is shipped after all) the first two letters capitalized.



  • @ender said:

    Even Microsoft isn't immune - Slovenian translation of Office 2010 installer had two letters transposed under the progress bar (which was really hard to miss), and in Windows 7 shutdown menu one entry had (well, has - those things don't get fixed once the product is shipped after all) the first two letters capitalized.

    To be fair, they probably figured Slovenians were too drunk to notice.



  • @ender said:

    Even Microsoft isn't immune - Slovenian translation of Office 2010 installer had two letters transposed under the progress bar (which was really hard to miss), and in Windows 7 shutdown menu one entry had (well, has - those things don't get fixed once the product is shipped after all) the first two letters capitalized.

    Two minor easily-overlooked errors in a language nobody speaks? PROOF POSITIVE MICROSOFT SOFTWARE IS WORSE THAN OPEN SOURCE!



  • @blakeyrat said:

    Two minor easily-overlooked errors in a language nobody speaks? PROOF POSITIVE MICROSOFT SOFTWARE IS WORSE THAN OPEN SOURCE!
    Their localization capabilities are certainly worse than gettext's - there's no support for plural forms at all, which results in awkward wording everywhere where counting is involved.



  • Or maybe this is when people should start arguing that English becomes the universal language of computing?

    I always personify English as a jerk because of what German did to it in the 15th century. "Hey, German, remember when you turned all my þ's into y's? Well say goodbye to your precious ß!"



  • @MiffTheFox said:

    Or maybe this is when people should start arguing that English becomes the universal language of computing?

    I think it should be the universal language of everything. Why should we waste resources catering software for countries that only have a single computer? We have nukes, we have ASCII, I think the solution is obvious.



  • @dkf said:

    @morbiuswilters said:
    "referer"
    Please consider my teeth to be duly ground.

    When I first saw that I just thought it was the American spelling. Since you guys have removed lots of double letters like from "cancelled" or "dialler".



  • @morbiuswilters said:

    @MiffTheFox said:
    Or maybe this is when people should start arguing that English becomes the universal language of computing?

    I think it should be the universal language of everything.

    Sometimes I think that too, but then I remember that English is TRWTF.



  • @Zemm said:

    @dkf said:
    @morbiuswilters said:
    "referer"
    Please consider my teeth to be duly ground.

    When I first saw that I just thought it was the American spelling. Since you guys have removed lots of double letters like from "cancelled" or "dialler".

     

    Or "tumbler".


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.