• Creating/comparing a hashed password in YottaDB

    From rtweed@21:1/5 to All on Thu Oct 29 08:59:21 2020
    In Node.js I can use a module named bcrypt to create a hashed password and to subsequently check/compare a password attempt against it, eg:

    let salt = bcrypt.genSaltSync(10);
    let password_hash = bcrypt.hashSync(password, salt);


    let matched = bcrypt.compareSync(password, password_hash);

    How would I be able to achieve the same functionality in M code using YottaDB? I guess it's a case of a piped call to an external command?

    Many thanks for any suggestions

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From K.S. Bhaskar@21:1/5 to rtweed on Thu Oct 29 10:29:13 2020
    On Thursday, October 29, 2020 at 11:59:23 AM UTC-4, rtweed wrote:
    In Node.js I can use a module named bcrypt to create a hashed password and to subsequently check/compare a password attempt against it, eg:

    let salt = bcrypt.genSaltSync(10);
    let password_hash = bcrypt.hashSync(password, salt);


    let matched = bcrypt.compareSync(password, password_hash);

    How would I be able to achieve the same functionality in M code using YottaDB? I guess it's a case of a piped call to an external command?

    Many thanks for any suggestions

    https://docs.yottadb.com/ProgrammersGuide/functions.html#zyhash

    set x="How can I hash thee? Let me count the ways",y=$zut#(2**32) zwrite x,y
    x="How can I hash thee? Let me count the ways"
    y=2632955533

    write $zyhash(x,y)
    0xcf397e77116602fe49cd8097a932e953


    Regards
    – Bhaskar

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to All on Thu Oct 29 11:32:24 2020
    Thanks Bhaskar

    How would I do the compare, given that I won't know the salt value originally used to hash the password?

    bcrypt's compare() appears to figure that out for me automagically

    Rob

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to All on Thu Oct 29 13:10:00 2020
    Looks like bcrypt incorporates the salt into the hash:

    https://medium.com/javascript-in-plain-english/how-bcryptjs-works-90ef4cb85bf4

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From K.S. Bhaskar@21:1/5 to rtweed on Thu Oct 29 12:45:31 2020
    On Thursday, October 29, 2020 at 2:32:26 PM UTC-4, rtweed wrote:
    Thanks Bhaskar

    How would I do the compare, given that I won't know the salt value originally used to hash the password?

    bcrypt's compare() appears to figure that out for me automagically

    Rob

    If bcrypt can figure out the hash during compare, it has to use a known salt. Depending on the use case, it may be the date, something based on the userid, etc., or maybe just zero. If the salt can be reverse engineered from the hash, that's a pretty
    useless salt, or a pretty useless hash, or both.

    Regards
    – Bhaskar

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to rtweed on Thu Oct 29 13:19:25 2020
    On Thursday, 29 October 2020 20:10:01 UTC, rtweed wrote:
    Looks like bcrypt incorporates the salt into the hash:

    https://medium.com/javascript-in-plain-english/how-bcryptjs-works-90ef4cb85bf4

    and further implementation information here:

    https://stackoverflow.com/questions/13023361/how-does-node-bcrypt-js-compare-hashed-and-plaintext-passwords-without-the-salt

    I think I can do something similar using zyhash

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From K.S. Bhaskar@21:1/5 to rtweed on Thu Oct 29 13:29:04 2020
    On Thursday, October 29, 2020 at 4:19:26 PM UTC-4, rtweed wrote:
    On Thursday, 29 October 2020 20:10:01 UTC, rtweed wrote:
    Looks like bcrypt incorporates the salt into the hash:

    https://medium.com/javascript-in-plain-english/how-bcryptjs-works-90ef4cb85bf4

    and further implementation information here:

    https://stackoverflow.com/questions/13023361/how-does-node-bcrypt-js-compare-hashed-and-plaintext-passwords-without-the-salt

    I think I can do something similar using zyhash

    What bcrypt is doing has a laudable goal But from a security point of view the salt adds no flavor to the hash. You may as well leave it unsalted.

    A better technique, e.g., if your hashing the password for a userid, is to create an unsalted hash of the userid, take the first 4 bytes, and use that as the salt for $zyhash().

    Regards
    – Bhaskar

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sam Habiel@21:1/5 to K.S. Bhaskar on Fri Oct 30 05:15:17 2020
    On Thursday, October 29, 2020 at 4:29:05 PM UTC-4, K.S. Bhaskar wrote:
    On Thursday, October 29, 2020 at 4:19:26 PM UTC-4, rtweed wrote:
    On Thursday, 29 October 2020 20:10:01 UTC, rtweed wrote:
    Looks like bcrypt incorporates the salt into the hash:

    https://medium.com/javascript-in-plain-english/how-bcryptjs-works-90ef4cb85bf4

    and further implementation information here:

    https://stackoverflow.com/questions/13023361/how-does-node-bcrypt-js-compare-hashed-and-plaintext-passwords-without-the-salt

    I think I can do something similar using zyhash
    What bcrypt is doing has a laudable goal But from a security point of view the salt adds no flavor to the hash. You may as well leave it unsalted.

    A better technique, e.g., if your hashing the password for a userid, is to create an unsalted hash of the userid, take the first 4 bytes, and use that as the salt for $zyhash().

    Regards
    – Bhaskar
    Rob, Bhaskar,

    This article can clarify things:
    https://crackstation.net/hashing-security.htm

    For YottaDB, $zyhash is not secure.

    Salts are invented by the application and can be any static value that ideally differs between each user. A user number is a good value to use.

    The proper way to do it is to implement a C call-out to libsodium (https://doc.libsodium.org/). I wanted to do that someday, but never got to do it.

    --Sam

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to All on Fri Oct 30 07:25:31 2020
    Auth0, who are pretty highly regarded for their security credentials, seem to be OK with bcrypt:

    https://auth0.com/blog/hashing-in-action-understanding-bcrypt/

    Something YottaDB could do with is an integrated set of crypto functions/procedures - they're pretty essential these days particularly for web-related work.

    On the rare occasions I have to return to programming in M, it's the lack of standard utility libraries (which you simply take for granted will be there in other languages) that make life difficult. So many times we end up re-inventing the same old
    wheels in M as a result.

    BTW if $zyhash isn't secure, what's the use-case it's designed for?

    Rob

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From K.S. Bhaskar@21:1/5 to Sam Habiel on Fri Oct 30 07:26:05 2020
    On Friday, October 30, 2020 at 8:15:18 AM UTC-4, Sam Habiel wrote:
    On Thursday, October 29, 2020 at 4:29:05 PM UTC-4, K.S. Bhaskar wrote:
    On Thursday, October 29, 2020 at 4:19:26 PM UTC-4, rtweed wrote:
    On Thursday, 29 October 2020 20:10:01 UTC, rtweed wrote:
    Looks like bcrypt incorporates the salt into the hash:

    https://medium.com/javascript-in-plain-english/how-bcryptjs-works-90ef4cb85bf4

    and further implementation information here:

    https://stackoverflow.com/questions/13023361/how-does-node-bcrypt-js-compare-hashed-and-plaintext-passwords-without-the-salt

    I think I can do something similar using zyhash
    What bcrypt is doing has a laudable goal But from a security point of view the salt adds no flavor to the hash. You may as well leave it unsalted.

    A better technique, e.g., if your hashing the password for a userid, is to create an unsalted hash of the userid, take the first 4 bytes, and use that as the salt for $zyhash().

    Regards
    – Bhaskar
    Rob, Bhaskar,

    This article can clarify things: https://crackstation.net/hashing-security.htm

    For YottaDB, $zyhash is not secure.

    Salts are invented by the application and can be any static value that ideally differs between each user. A user number is a good value to use.

    The proper way to do it is to implement a C call-out to libsodium (https://doc.libsodium.org/). I wanted to do that someday, but never got to do it.

    --Sam

    Sam, the YottaDB hashing algorithm is the MMRHash, which has good statistical properties, but is not a cryptographic hash. The $zyhash() documentation states that, and I should have noted that in my response to Rob.

    Regards
    – Bhaskar

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From K.S. Bhaskar@21:1/5 to rtweed on Fri Oct 30 07:28:52 2020
    On Friday, October 30, 2020 at 10:25:32 AM UTC-4, rtweed wrote:
    Auth0, who are pretty highly regarded for their security credentials, seem to be OK with bcrypt:

    https://auth0.com/blog/hashing-in-action-understanding-bcrypt/

    Something YottaDB could do with is an integrated set of crypto functions/procedures - they're pretty essential these days particularly for web-related work.

    On the rare occasions I have to return to programming in M, it's the lack of standard utility libraries (which you simply take for granted will be there in other languages) that make life difficult. So many times we end up re-inventing the same old
    wheels in M as a result.

    BTW if $zyhash isn't secure, what's the use-case it's designed for?

    Rob

    There are numerous non-cryptographic applications for hashing. The MMRHash implemented by $zyhash() is fast and has excellent statistical properties, which make it suitable as a general purpose hash, but not a cryptographic hash. I should have stated
    that in my response.

    Regards
    – Bhaskar

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to All on Fri Oct 30 10:41:27 2020
    OK I've been hacking around and this kind of idea seems to work. It requires me to first do an

    apt-get install apache2-utils

    but after that it seems to work OK

    bcryptHash(username,password) ;
    ;
    n msg
    ;
    i $zv["GT.M" d
    . n name,str
    . s name="bcrypt"
    . s str="open name:(command=""htpasswd -cbBC 10 /opt/qewd/passwd "_username_" "_password_""":readonly)::""pipe"""
    . x str
    . use name read msg u $principal close name
    QUIT msg
    ;
    bcryptVerify(username,password) ;
    ;
    n msg,ok
    ;
    i $zv["GT.M" d
    . n name,str
    . s name="bcrypt"
    . s str="open name:(command=""htpasswd -vbC 10 /opt/qewd/passwd "_username_" "_password_""":readonly)::""pipe"""
    . x str
    . use name read msg u $principal close name
    . s ok=0
    . i msg["Password for user "_username_" correct" s ok=1
    QUIT ok
    ;

    One question on the Verify function - As you can see I'm checking the output string from htpasswd to confirm whether the password verified or not. I've read that the status code returned by htpasswd is 1 if it verified, 0 if not. It would be better to
    use this if possible. However, it's not clear to me how/where I can obtain that status code via the piped device. Any ideas?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From OldMster@21:1/5 to rtweed on Fri Oct 30 11:19:05 2020
    On Friday, October 30, 2020 at 1:41:28 PM UTC-4, rtweed wrote:
    OK I've been hacking around and this kind of idea seems to work. It requires me to first do an

    apt-get install apache2-utils

    but after that it seems to work OK

    bcryptHash(username,password) ;
    ;
    n msg
    ;
    i $zv["GT.M" d
    . n name,str
    . s name="bcrypt"
    . s str="open name:(command=""htpasswd -cbBC 10 /opt/qewd/passwd "_username_" "_password_""":readonly)::""pipe"""
    . x str
    . use name read msg u $principal close name
    QUIT msg
    ;
    bcryptVerify(username,password) ;
    ;
    n msg,ok
    ;
    i $zv["GT.M" d
    . n name,str
    . s name="bcrypt"
    . s str="open name:(command=""htpasswd -vbC 10 /opt/qewd/passwd "_username_" "_password_""":readonly)::""pipe"""
    . x str
    . use name read msg u $principal close name
    . s ok=0
    . i msg["Password for user "_username_" correct" s ok=1
    QUIT ok
    ;

    One question on the Verify function - As you can see I'm checking the output string from htpasswd to confirm whether the password verified or not. I've read that the status code returned by htpasswd is 1 if it verified, 0 if not. It would be better
    to use this if possible. However, it's not clear to me how/where I can obtain that status code via the piped device. Any ideas?

    Rob, try this:

    s str="open name:(command=""htpasswd -cbBC 10 /opt/qewd/passwd "_username_" "_password_"" ; echo 'success: '$? ":readonly)::""pipe"""

    The last line of the piped input should be 'success: 0' if it failed, and 'success: 1' if it succeeded.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to OldMster on Fri Oct 30 11:39:03 2020
    On Friday, 30 October 2020 18:19:07 UTC, OldMster wrote:
    On Friday, October 30, 2020 at 1:41:28 PM UTC-4, rtweed wrote:
    OK I've been hacking around and this kind of idea seems to work. It requires me to first do an

    apt-get install apache2-utils

    but after that it seems to work OK

    bcryptHash(username,password) ;
    ;
    n msg
    ;
    i $zv["GT.M" d
    . n name,str
    . s name="bcrypt"
    . s str="open name:(command=""htpasswd -cbBC 10 /opt/qewd/passwd "_username_" "_password_""":readonly)::""pipe"""
    . x str
    . use name read msg u $principal close name
    QUIT msg
    ;
    bcryptVerify(username,password) ;
    ;
    n msg,ok
    ;
    i $zv["GT.M" d
    . n name,str
    . s name="bcrypt"
    . s str="open name:(command=""htpasswd -vbC 10 /opt/qewd/passwd "_username_" "_password_""":readonly)::""pipe"""
    . x str
    . use name read msg u $principal close name
    . s ok=0
    . i msg["Password for user "_username_" correct" s ok=1
    QUIT ok
    ;

    One question on the Verify function - As you can see I'm checking the output string from htpasswd to confirm whether the password verified or not. I've read that the status code returned by htpasswd is 1 if it verified, 0 if not. It would be better
    to use this if possible. However, it's not clear to me how/where I can obtain that status code via the piped device. Any ideas?

    Rob, try this:

    s str="open name:(command=""htpasswd -cbBC 10 /opt/qewd/passwd "_username_" "_password_"" ; echo 'success: '$? ":readonly)::""pipe"""

    The last line of the piped input should be 'success: 0' if it failed, and 'success: 1' if it succeeded.

    Awesome! Thanks Mark!!

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Antoine Koener@21:1/5 to All on Wed Nov 4 01:57:00 2020
    Le vendredi 30 octobre 2020 à 19:39:05 UTC+1, rtweed a écrit :
    On Friday, 30 October 2020 18:19:07 UTC, OldMster wrote:
    On Friday, October 30, 2020 at 1:41:28 PM UTC-4, rtweed wrote:
    OK I've been hacking around and this kind of idea seems to work. It requires me to first do an

    apt-get install apache2-utils

    but after that it seems to work OK

    bcryptHash(username,password) ;
    ;
    n msg
    ;
    i $zv["GT.M" d
    . n name,str
    . s name="bcrypt"
    . s str="open name:(command=""htpasswd -cbBC 10 /opt/qewd/passwd "_username_" "_password_""":readonly)::""pipe"""
    . x str
    . use name read msg u $principal close name
    QUIT msg
    ;
    bcryptVerify(username,password) ;
    ;
    n msg,ok
    ;
    i $zv["GT.M" d
    . n name,str
    . s name="bcrypt"
    . s str="open name:(command=""htpasswd -vbC 10 /opt/qewd/passwd "_username_" "_password_""":readonly)::""pipe"""
    . x str
    . use name read msg u $principal close name
    . s ok=0
    . i msg["Password for user "_username_" correct" s ok=1
    QUIT ok
    ;

    One question on the Verify function - As you can see I'm checking the output string from htpasswd to confirm whether the password verified or not. I've read that the status code returned by htpasswd is 1 if it verified, 0 if not. It would be better
    to use this if possible. However, it's not clear to me how/where I can obtain that status code via the piped device. Any ideas?

    Rob, try this:

    s str="open name:(command=""htpasswd -cbBC 10 /opt/qewd/passwd "_username_" "_password_"" ; echo 'success: '$? ":readonly)::""pipe"""

    The last line of the piped input should be 'success: 0' if it failed, and 'success: 1' if it succeeded.
    Awesome! Thanks Mark!!

    Beware that username nor password may contains Shell parameters ...
    This seems to me to be a trivial shell injection here.
    Nope ?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to All on Wed Nov 4 05:36:11 2020
    So what would you suggest instead?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to All on Wed Nov 4 05:41:33 2020
    I guess that's a general problem with the pipe device mechanism where it's being used to call out to shell commands. Personally I'd prefer to have M functions that implement these kinds of things.

    Anyone want to suggest some logic to prevent shell command injection via a username/password entered into a web form?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to rtweed on Wed Nov 4 06:09:34 2020
    On Wednesday, 4 November 2020 13:41:34 UTC, rtweed wrote:
    I guess that's a general problem with the pipe device mechanism where it's being used to call out to shell commands. Personally I'd prefer to have M functions that implement these kinds of things.

    Anyone want to suggest some logic to prevent shell command injection via a username/password entered into a web form?

    eg I guess it would be wise to ensure that neither a username nor password must contain spaces or punctuation characters, and be limited to the characters A-Za-z0-9 ?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From K.S. Bhaskar@21:1/5 to rtweed on Wed Nov 4 09:10:14 2020
    On Wednesday, November 4, 2020 at 8:41:34 AM UTC-5, rtweed wrote:
    I guess that's a general problem with the pipe device mechanism where it's being used to call out to shell commands. Personally I'd prefer to have M functions that implement these kinds of things.

    Anyone want to suggest some logic to prevent shell command injection via a username/password entered into a web form?

    Since M is a programming language, you can do anything you want, and the onus is on the application program to validate inputs (see https://xkcd.com/327/). Perhaps the application can pass the username and password as inputs to whatever command you run
    in the PIPE device, rather than putting them on the command line.

    Regards
    – Bhaskar

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to K.S. Bhaskar on Thu Nov 5 01:00:51 2020
    On Wednesday, 4 November 2020 at 17:10:16 UTC, K.S. Bhaskar wrote:
    On Wednesday, November 4, 2020 at 8:41:34 AM UTC-5, rtweed wrote:
    I guess that's a general problem with the pipe device mechanism where it's being used to call out to shell commands. Personally I'd prefer to have M functions that implement these kinds of things.

    Anyone want to suggest some logic to prevent shell command injection via a username/password entered into a web form?
    Since M is a programming language, you can do anything you want, and the onus is on the application program to validate inputs (see https://xkcd.com/327/). Perhaps the application can pass the username and password as inputs to whatever command you run
    in the PIPE device, rather than putting them on the command line.

    Regards
    – Bhaskar

    Could you give an example of what you mean, Bhaskar?

    Anyone else have any suggestions for what is clearly a generic issue when using pipe devices for crypto functions needed in web apps (eg for JWTs signatures, password hashing, etc). It would be good if some community best practice could be put together
    rather than us all guessing and reinventing our own wheels as usual in the M world (which is, to be honest, why I prefer the Node.js world)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to All on Thu Nov 5 01:25:02 2020
    Just to expand on this: so my logic for this kind of thing now looks like this example

    . s command="htpasswd -cbBC 10 "_filename_" "_username_" "_password
    . open name:(command=command:readonly)::"pipe"

    In this case using the htpasswd command for bcrypt passwpord hashing. The filename and username values in the example above are now internally-constructed values so can't be messed with by a user.

    The question is whether the user-provided password value could be subject to being subverted to do command injection - thus invoking not just the htpasswd command but any additional arbitrary ones defined in the password value. It strikes me that
    provided certain characters were prevented from being allowed in the password value - for example spaces, semi-colons, pipe character, backslash (escape), open and close parens - then it shouldn't be possible to engineer a way to use the password value
    to construct additional commands in the generated "command" variable string.

    Any thoughts?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sam Habiel@21:1/5 to rtweed on Thu Nov 5 04:57:05 2020
    On Thursday, November 5, 2020 at 4:25:04 AM UTC-5, rtweed wrote:
    Just to expand on this: so my logic for this kind of thing now looks like this example

    . s command="htpasswd -cbBC 10 "_filename_" "_username_" "_password
    . open name:(command=command:readonly)::"pipe"

    In this case using the htpasswd command for bcrypt passwpord hashing. The filename and username values in the example above are now internally-constructed values so can't be messed with by a user.

    The question is whether the user-provided password value could be subject to being subverted to do command injection - thus invoking not just the htpasswd command but any additional arbitrary ones defined in the password value. It strikes me that
    provided certain characters were prevented from being allowed in the password value - for example spaces, semi-colons, pipe character, backslash (escape), open and close parens - then it shouldn't be possible to engineer a way to use the password value
    to construct additional commands in the generated "command" variable string.

    Any thoughts?
    Rob,

    From the security news you hear, somebody always figures out a way,
    for example, but using unicode escapes (\uxxxx). Micrososft IIS, for
    example, seems to have directory traversal bugs still that you hear
    coming out every few years because somebody figures out a way to do ..

    In the end, I would look at your risk profile and see what risk you
    can tolerate. If this is for an internal intranet application, you are
    probably safe. If you plan on deploying this for an internet connected
    website, you need to invest the time in writing a C callout to
    libsodium (https://doc.libsodium.org/), or relegating passwords to
    another provider via OAuth2, etc.

    If you are doing a demo application, I wrote an openSSL C wrapper (https://github.com/shabiel/fis-gtm-plugins/tree/master/openssl). It
    does md5 and the various shas via openssl.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Art@21:1/5 to Sam Habiel on Thu Nov 5 07:02:40 2020
    On Thursday, November 5, 2020 at 6:57:08 AM UTC-6, Sam Habiel wrote:
    On Thursday, November 5, 2020 at 4:25:04 AM UTC-5, rtweed wrote:
    Just to expand on this: so my logic for this kind of thing now looks like this example

    . s command="htpasswd -cbBC 10 "_filename_" "_username_" "_password
    . open name:(command=command:readonly)::"pipe"

    In this case using the htpasswd command for bcrypt passwpord hashing. The filename and username values in the example above are now internally-constructed values so can't be messed with by a user.

    The question is whether the user-provided password value could be subject to being subverted to do command injection - thus invoking not just the htpasswd command but any additional arbitrary ones defined in the password value. It strikes me that
    provided certain characters were prevented from being allowed in the password value - for example spaces, semi-colons, pipe character, backslash (escape), open and close parens - then it shouldn't be possible to engineer a way to use the password value
    to construct additional commands in the generated "command" variable string.

    Any thoughts?
    Rob,

    From the security news you hear, somebody always figures out a way,
    for example, but using unicode escapes (\uxxxx). Micrososft IIS, for
    example, seems to have directory traversal bugs still that you hear
    coming out every few years because somebody figures out a way to do ..

    In the end, I would look at your risk profile and see what risk you
    can tolerate. If this is for an internal intranet application, you are probably safe. If you plan on deploying this for an internet connected website, you need to invest the time in writing a C callout to
    libsodium (https://doc.libsodium.org/), or relegating passwords to
    another provider via OAuth2, etc.

    If you are doing a demo application, I wrote an openSSL C wrapper (https://github.com/shabiel/fis-gtm-plugins/tree/master/openssl). It
    does md5 and the various shas via openssl.

    Thank you Sam for this resource

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From K.S. Bhaskar@21:1/5 to rtweed on Thu Nov 5 07:37:00 2020
    On Thursday, November 5, 2020 at 4:25:04 AM UTC-5, rtweed wrote:
    Just to expand on this: so my logic for this kind of thing now looks like this example

    . s command="htpasswd -cbBC 10 "_filename_" "_username_" "_password
    . open name:(command=command:readonly)::"pipe"


    [KSB] If you use the -i option for htpasswd, you can pass the password on stdin to the htpasswd program, which provides a good way to pass the password securely as well as to prevent command injection.

    Regards
    – Bhaskar

    In this case using the htpasswd command for bcrypt passwpord hashing. The filename and username values in the example above are now internally-constructed values so can't be messed with by a user.

    The question is whether the user-provided password value could be subject to being subverted to do command injection - thus invoking not just the htpasswd command but any additional arbitrary ones defined in the password value. It strikes me that
    provided certain characters were prevented from being allowed in the password value - for example spaces, semi-colons, pipe character, backslash (escape), open and close parens - then it shouldn't be possible to engineer a way to use the password value
    to construct additional commands in the generated "command" variable string.

    Any thoughts?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From OldMster@21:1/5 to K.S. Bhaskar on Thu Nov 5 07:52:01 2020
    On Thursday, November 5, 2020 at 10:37:02 AM UTC-5, K.S. Bhaskar wrote:
    On Thursday, November 5, 2020 at 4:25:04 AM UTC-5, rtweed wrote:
    Just to expand on this: so my logic for this kind of thing now looks like this example

    . s command="htpasswd -cbBC 10 "_filename_" "_username_" "_password
    . open name:(command=command:readonly)::"pipe"


    [KSB] If you use the -i option for htpasswd, you can pass the password on stdin to the htpasswd program, which provides a good way to pass the password securely as well as to prevent command injection.

    Regards
    – Bhaskar

    In this case using the htpasswd command for bcrypt passwpord hashing. The filename and username values in the example above are now internally-constructed values so can't be messed with by a user.

    The question is whether the user-provided password value could be subject to being subverted to do command injection - thus invoking not just the htpasswd command but any additional arbitrary ones defined in the password value. It strikes me that
    provided certain characters were prevented from being allowed in the password value - for example spaces, semi-colons, pipe character, backslash (escape), open and close parens - then it shouldn't be possible to engineer a way to use the password value
    to construct additional commands in the generated "command" variable string.

    Any thoughts?

    You should also look at the 'expect' command in Linux (it isn't installed by default, but readily available). It is very useful when automating sftp transfers that use username/password authentication, I expect it would work here also.
    Mark

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From K.S. Bhaskar@21:1/5 to rtweed on Thu Nov 5 07:34:09 2020
    On Thursday, November 5, 2020 at 4:00:53 AM UTC-5, rtweed wrote:
    On Wednesday, 4 November 2020 at 17:10:16 UTC, K.S. Bhaskar wrote:
    On Wednesday, November 4, 2020 at 8:41:34 AM UTC-5, rtweed wrote:
    I guess that's a general problem with the pipe device mechanism where it's being used to call out to shell commands. Personally I'd prefer to have M functions that implement these kinds of things.

    Anyone want to suggest some logic to prevent shell command injection via a username/password entered into a web form?
    Since M is a programming language, you can do anything you want, and the onus is on the application program to validate inputs (see https://xkcd.com/327/). Perhaps the application can pass the username and password as inputs to whatever command you
    run in the PIPE device, rather than putting them on the command line.

    Regards
    – Bhaskar

    Could you give an example of what you mean, Bhaskar?

    [KSB] Rob, a simple example would be changing the password for a user. If you were to change it using usermod, the password would be on the command line (e.g., usermod -p <password> <userid>) executed by usermod and hence briefly visible to the world. If
    you were to change it using passwd, then the command line would be passwd <userid> and you would then feed it the password by writing to the PIPE device, so the password is visible only to the application process and the passwd process (and of course the
    OS).

    openssl for example, allows you to specify a password on the command line as well as via input provided to the program.

    Regards
    – Bhaskar

    Anyone else have any suggestions for what is clearly a generic issue when using pipe devices for crypto functions needed in web apps (eg for JWTs signatures, password hashing, etc). It would be good if some community best practice could be put
    together rather than us all guessing and reinventing our own wheels as usual in the M world (which is, to be honest, why I prefer the Node.js world)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From OldMster@21:1/5 to K.S. Bhaskar on Thu Nov 5 08:49:39 2020
    On Thursday, November 5, 2020 at 10:37:02 AM UTC-5, K.S. Bhaskar wrote:
    On Thursday, November 5, 2020 at 4:25:04 AM UTC-5, rtweed wrote:
    Just to expand on this: so my logic for this kind of thing now looks like this example

    . s command="htpasswd -cbBC 10 "_filename_" "_username_" "_password
    . open name:(command=command:readonly)::"pipe"


    [KSB] If you use the -i option for htpasswd, you can pass the password on stdin to the htpasswd program, which provides a good way to pass the password securely as well as to prevent command injection.

    Regards
    – Bhaskar

    In this case using the htpasswd command for bcrypt passwpord hashing. The filename and username values in the example above are now internally-constructed values so can't be messed with by a user.

    The question is whether the user-provided password value could be subject to being subverted to do command injection - thus invoking not just the htpasswd command but any additional arbitrary ones defined in the password value. It strikes me that
    provided certain characters were prevented from being allowed in the password value - for example spaces, semi-colons, pipe character, backslash (escape), open and close parens - then it shouldn't be possible to engineer a way to use the password value
    to construct additional commands in the generated "command" variable string.

    Any thoughts?

    I believe this will work:

    AUTHUTIL ; USER AUTHORIZATION UTILS
    ;
    bcryptHash(username,password) ;
    ;create/hash password for a given username
    ;
    n outcome
    s outcome="unknown"
    if $g(username)="" q:$q "username is blank" q
    if $g(password)="" q:$q "password is blank" q
    if $tr(username,"|; \$()","")'=username q:$q "invalid characters in username" q
    i $zv["GT.M" d q:$q outcome q
    . n name,str,prompt,eof,pwcount,cio
    . s cio=$i
    . s str="open name:(command=""htpasswd -cBC 10 /opt/qewd/passwd "_username_""":noreadonly):""PIPE"""
    . x str
    . s pwcount=0
    . s eof=0
    . f q:eof u name r prompt:1 s eof=$zeof q:prompt["error" q:prompt[username w:prompt["password:" password,!
    . c name u cio
    . if prompt["error" s outcome="password verification failure" q
    . if prompt["Adding",prompt[username s outcome="password for user "_username_" added successfully" q
    . s outcome="unknown - last prompt was "_prompt
    q:$q outcome q

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From OldMster@21:1/5 to K.S. Bhaskar on Thu Nov 5 08:46:55 2020
    On Thursday, November 5, 2020 at 10:37:02 AM UTC-5, K.S. Bhaskar wrote:
    On Thursday, November 5, 2020 at 4:25:04 AM UTC-5, rtweed wrote:
    Just to expand on this: so my logic for this kind of thing now looks like this example

    . s command="htpasswd -cbBC 10 "_filename_" "_username_" "_password
    . open name:(command=command:readonly)::"pipe"


    [KSB] If you use the -i option for htpasswd, you can pass the password on stdin to the htpasswd program, which provides a good way to pass the password securely as well as to prevent command injection.

    Regards
    – Bhaskar

    In this case using the htpasswd command for bcrypt passwpord hashing. The filename and username values in the example above are now internally-constructed values so can't be messed with by a user.

    The question is whether the user-provided password value could be subject to being subverted to do command injection - thus invoking not just the htpasswd command but any additional arbitrary ones defined in the password value. It strikes me that
    provided certain characters were prevented from being allowed in the password value - for example spaces, semi-colons, pipe character, backslash (escape), open and close parens - then it shouldn't be possible to engineer a way to use the password value
    to construct additional commands in the generated "command" variable string.

    Any thoughts?

    I had some problems with the -i option, probably not holding my mouth exactly the way Linux wants it.

    I believe this should work though. Reduces the injection possibility to just the username, and doesn't make useful characters not usable for passwords. The same mechanism could be used for the verify.

    AUTHUTIL ; USER AUTHORIZATION UTILS
    ;
    bcryptHash(username,password) ;
    ;create/hash password for a given username
    ;
    n outcome
    s outcome="unknown"
    if $g(username)="" q:$q "username is blank" q
    if $g(password)="" q:$q "password is blank" q
    if $tr(username,"|; \$()","")'=username q:$q "invalid characters in username" q
    i $zv["GT.M" d q:$q outcome q
    . n name,str,prompt,eof,pwcount,cio
    . s cio=$i
    . s str="open name:(command=""htpasswd -cBC 10 /opt/qewd/passwd "_username_""":noreadonly):""PIPE"""
    . x str
    . s pwcount=0
    . f u name r prompt:1 s eof=$zeof q:prompt["error" q:prompt[username w:prompt["password:" password,!
    . c name u cio
    . if prompt["error" s outcome="password verification failure" q
    . if prompt["Adding",prompt[username s outcome="password for user "_username_" added successfully" q
    . s outcome="unknown - last prompt was "_prompt
    q:$q outcome q

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From OldMster@21:1/5 to kirk....@gmail.com on Thu Nov 5 17:02:43 2020
    On Thursday, November 5, 2020 at 7:47:19 PM UTC-5, kirk....@gmail.com wrote:
    Rob,
    Could you simply html/XML encode the password before sending it?
    I really hate sites not letting me use any character for a password.
    Once encoded, even if bad intentions, it should be rendered harmless.

    Just a thought.
    Hope all is well with you.
    Karl

    I didn't point out that the last example I posted would not exclude any character from the password, only the username, which I wouldn't consider a bad thing. Unless the artist formerly known as Prince wanted to use my web site (from the great beyond I
    guesss).

    Mark

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From kirk.karl.k@gmail.com@21:1/5 to All on Thu Nov 5 16:47:18 2020
    Rob,
    Could you simply html/XML encode the password before sending it?
    I really hate sites not letting me use any character for a password.
    Once encoded, even if bad intentions, it should be rendered harmless.

    Just a thought.
    Hope all is well with you.
    Karl

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to All on Fri Nov 6 01:42:41 2020
    Rob,
    Could you simply html/XML encode the password before sending it?
    I really hate sites not letting me use any character for a password.
    Once encoded, even if bad intentions, it should be rendered harmless.

    Just a thought.
    Hope all is well with you.
    Karl

    Hi Karl
    Interesting idea - base64 encoding would be a perhaps more sensible thing to use... except that would also often be done using a pipe device call to the base64 command! One step forward, one step back :-)

    I thank Antoine Koener for highlighting this issue - it's one of those things that's blindingly obvious once pointed out, but I'd certainly not considered the potential risks until he did.

    I'm pleased to see the ideas and contributions to this. I think perhaps a warning should be added to the YottaDB documentation about the potential risks (with a simple example) of command line prompt injection when using pipe devices, with perhaps some
    simple worked examples of how they can be prevented.

    I still think a set of community-agreed crypto/encoding/decoding functions for YottaDB using best practices should be put together, so people aren't re-inventing the same wheels with the risk of inadvertently/naively leaving themselves open to security
    risks.

    The project I'm currently working on (to be revealed soon I'm hoping) may provide an initial starting point as it will include most of the key crypto/encode/decode examples needed these days. I'll be happy to have the code I initially use ripped apart
    and replaced by better/safer versions

    Rob

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to All on Fri Nov 6 04:38:12 2020
    OK so the -i directive suggested by Bhaskar seems to be a sensible approach. Here's my latest versions:

    1) hashing a password:

    i $zv["GT.M" d
    . n command,filename,msg,name,username
    . s name="bcrypt"
    . s username="dummy"
    . s filename="/opt/mgweb/passwd"_$j
    . i $$deleteFile(filename)
    . ;s command="htpasswd -cbBC 10 "_filename_" "_username_" "_password
    . ;open name:(command=command:readonly)::"pipe"
    . ;use name read msg u $principal close name
    . s command="htpasswd -cbBC 10 -i "_filename_" "_username
    . open name:(command=command)::"pipe"
    . use name w password,! w /EOF
    . u name r msg
    . u $principal close name
    . i $$openFile(filename);
    . u filename r hash c filename
    . u $principal
    . i $$deleteFile(filename)
    . s hash=$p(hash,username_":",2)
    QUIT hash

    Note the way I create a temporary file and a dummy username. Also note how the command line is now fixed and
    not subject to being tampered with

    2) Verifying a password:

    Uses the reverse, constructing a temporary file with a hashed contents including the dummy username:

    i $zv["GT.M" d
    . n command,filename,msg,name,success,username
    . s name="bcrypt"
    . s username="dummy"
    . s filename="/opt/mgweb/passwd"_$j
    . i $$openNewFile(filename)
    . u filename w username_":"_hash,! c filename
    . s command="htpasswd -vbC 10 -i "_filename_" "_username_" ; echo $?"
    . open name:(command=command)::"pipe"
    . u name w password,! w /EOF
    . use name read msg,success
    . u $principal close name
    . s ok=(success=+0)
    . i $$deleteFile(filename)
    QUIT ok

    Returns 0 if failed, 1 if password matched against the hash

    As you can see I've packaged up the file handling commands inside extrinsic functions, but they just use the standard YottaDB device handling logic inside them for opening and deleting files.

    So I think these two functions are pretty bullet-proof implementations of the bcrypt algorithm

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From rtweed@21:1/5 to All on Fri Nov 6 04:51:58 2020
    Check $ZCLOSE to see the status of the command. echo $? isn't needed.

    Sam, could you show the appropriately amended code per your suggestion please?

    In general I'd prefer people show worked-out (and ideally tested) code rather than a "do x instead" response,
    Saves me (and potentially others) a lot of messing about and guesswork if we can see actual code examples.
    Thanks :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sam Habiel@21:1/5 to rtweed on Fri Nov 6 04:44:31 2020
    On Friday, November 6, 2020 at 7:38:13 AM UTC-5, rtweed wrote:
    OK so the -i directive suggested by Bhaskar seems to be a sensible approach. Here's my latest versions:

    1) hashing a password:

    i $zv["GT.M" d
    . n command,filename,msg,name,username
    . s name="bcrypt"
    . s username="dummy"
    . s filename="/opt/mgweb/passwd"_$j
    . i $$deleteFile(filename)
    . ;s command="htpasswd -cbBC 10 "_filename_" "_username_" "_password
    . ;open name:(command=command:readonly)::"pipe"
    . ;use name read msg u $principal close name
    . s command="htpasswd -cbBC 10 -i "_filename_" "_username
    . open name:(command=command)::"pipe"
    . use name w password,! w /EOF
    . u name r msg
    . u $principal close name
    . i $$openFile(filename);
    . u filename r hash c filename
    . u $principal
    . i $$deleteFile(filename)
    . s hash=$p(hash,username_":",2)
    QUIT hash

    Note the way I create a temporary file and a dummy username. Also note how the command line is now fixed and
    not subject to being tampered with

    2) Verifying a password:

    Uses the reverse, constructing a temporary file with a hashed contents including the dummy username:

    i $zv["GT.M" d
    . n command,filename,msg,name,success,username
    . s name="bcrypt"
    . s username="dummy"
    . s filename="/opt/mgweb/passwd"_$j
    . i $$openNewFile(filename)
    . u filename w username_":"_hash,! c filename
    . s command="htpasswd -vbC 10 -i "_filename_" "_username_" ; echo $?"
    . open name:(command=command)::"pipe"
    . u name w password,! w /EOF
    . use name read msg,success
    . u $principal close name
    . s ok=(success=+0)
    . i $$deleteFile(filename)
    QUIT ok

    Returns 0 if failed, 1 if password matched against the hash

    As you can see I've packaged up the file handling commands inside extrinsic functions, but they just use the standard YottaDB device handling logic inside them for opening and deleting files.

    So I think these two functions are pretty bullet-proof implementations of the bcrypt algorithm
    Check $ZCLOSE to see the status of the command. echo $? isn't needed.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sam Habiel@21:1/5 to rtweed on Fri Nov 6 05:05:20 2020
    On Friday, November 6, 2020 at 7:51:59 AM UTC-5, rtweed wrote:
    Check $ZCLOSE to see the status of the command. echo $? isn't needed.
    Sam, could you show the appropriately amended code per your suggestion please?

    In general I'd prefer people show worked-out (and ideally tested) code rather than a "do x instead" response,
    Saves me (and potentially others) a lot of messing about and guesswork if we can see actual code examples.
    Thanks :-)
    Okay... quickly... for one of the lines here:

    . s command="htpasswd -vbC 10 -i "_filename_" "_username ; (remove echo $?) ...
    . s ok=$zclose ; was s ok=(success=+0)

    That's the pattern.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)