dropbox / zxcvbn-ios

A realistic password strength estimator.
https://tech.dropbox.com/2012/04/zxcvbn-realistic-password-strength-estimation/
MIT License
223 stars 64 forks source link

zxcvbn-ios scores password differently than zxcvbn #21

Open dylanhand opened 8 years ago

dylanhand commented 8 years ago

Hi Leah. Thanks for porting this to iOS. I came across a potential issue:

The password 2-UbvR, for example, is scored differently on zxvcbn-ios vs. Dropbox's online zxcvbn test.

Dropbox's online test: screen_shot_2016-06-15_at_12_45_33_pm

zxcvbn-ios:

screen shot 2016-06-15 at 12 53 38 pm

Any idea why the iOS version would score a password differently?

mlehel commented 8 years ago

Exactly what I have experienced as well, the iOS library scores passwords differently than the JS version, it always gives them a lower scores as far as I could see. Please advise.

mlehel commented 8 years ago

Anybody? Any input would be greatly appreciated.

billymeltdown commented 8 years ago

@mlehel Couldn't tell you myself, but you could step through the routine in a debugger in one lib, then do the same in the debugger for another of the libs to find out what choices are being made differently. For example in iOS you could set a breakpoint where your code calls score and step in. For debugging Javascript you might be able to use your browser, and there's tools like Firebug. For stepping through the Python library you could use the pdb module.

I know that's not answers, but I watch the project and saw your posts so I thought I'd reply. That's where I'd start, I hope it helps!

mlehel commented 8 years ago

@billymeltfown: thank you very much for you input, I'll take a look at it, in the meantime I'm also looking forward to some input on behalf of the creators of this module

mlehel commented 7 years ago

@dylanhand did you get anywhere with this issue?

dylanhand commented 7 years ago

@mlehel no. Still hoping we'll hear something from @dropbox or @leah :)

patreu22 commented 7 years ago

I'm facing the same problem. The original version rates the password "hell\o/12" with a score of 2 and "hell\o/123" with a score of 3.

The iOS port accepts "hell\o/12" as a score 3 password and says "hell\o/123" is weaker (only a score of 2).

Does anybody still contribute on this project?

dylanhand commented 7 years ago

@patreu22 @mlehel I ended up using the JavaScript version inside a JSContext. This way you get consistent results while still running locally.

import JavaScriptCore // make sure to add the framework to your project

fileprivate let jsContext: JSContext! = JSContext()    

// in init:
// load zxvcbn for determining password strength
let zxcvbnPath = Bundle.main.path(forResource: "zxcvbn", ofType: "js")
do {
    let zxcvbnJS = try String(contentsOfFile: zxcvbnPath!, encoding: String.Encoding.utf8)
    jsContext.evaluateScript(zxcvbnJS)
} catch {
    print("error reading zxcvbn.js")
}

// run our local JS zxcvbn function to determine password strength
let password = "hell\o/123"
let result = jsContext.evaluateScript("zxcvbn('\(password)')")
let score = result?.objectForKeyedSubscript("score").toInt32()
lowe commented 7 years ago

Hi @mlehel,

There's two big reasons that zxcvbn and zxcvbn-ios sometimes give different results:

If you want the latest updates, I'd recommend using @dylanhand's approach or similar.

patreu22 commented 7 years ago

Hey @dylanhand , thanks a lot for your help, using the JavaScript version was our plan to fix that problem, so thank you :)

likekunkun commented 5 years ago

@dylanhand Thanks 。 I have used your method,However,my score allways -> 0. Do you know what the reason is?

likekunkun commented 5 years ago

@patreu22 I have used those method, however score always ->0,
Can you help me. thanks

AKoulabukhov commented 5 years ago

@likekunkun there is one problem with @dylanhand approach. Using String Interpolation is not safe, because password itself can contain ' or ) symbols which would break JS statement.

So instead you should set your password directly into JSContext as variable and then use this variable in evaluateScript. Here is sample code:

    func getPasswordScore(_ password: String) throws -> Int32 {
        guard let jsContext = JSContext() else { throw NSError() }

        // Load zxcvbn into JSContext
        guard let zxcvbnPath = Bundle.main.path(forResource: "zxcvbn", ofType: "js") else { throw NSError() }
        let zxcvbnJS = try String(contentsOfFile: zxcvbnPath, encoding: String.Encoding.utf8)
        jsContext.evaluateScript(zxcvbnJS)

        // Set password to context, evaluate script and get result
        jsContext.setObject(password, forKeyedSubscript: "password" as NSString)
        guard
            let result = jsContext.evaluateScript("zxcvbn(password)"),
            let value = result.objectForKeyedSubscript("score")
            else { throw NSError() }

        return value.toInt32()
    }