Why won't my SQL passwordhashing-procedure run? - mysql

I am trying to create a SQL procedure that hashes password inputs. This code won't run and I am not getting any useful response errors.
The first part creates the table, the second creates the procedure. When I call on my procedure in the third part it send the values into the procedure. There the password is supposed to be hashed using SHA2_512 and inserted into the table we made eralier.
I used online research to make this code, the parts I don't get is:
The N before my values
The SetNoCount
The #responsemessage
-- makes Admin table
CREATE TABLE IF NOT EXISTS `AdminUser` (
`AdminID` smallint(6) NOT NULL AUTO_INCREMENT,
`Username` char(15) NOT NULL,
`PasswordHash` BINARY(64) NOT NULL,
`Fornavn` char(30) NOT NULL,
`Etternavn` char(40) NOT NULL,
`Email` char(40) NOT NULL,
PRIMARY KEY (`AdminID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Makes hashing procedure
CREATE OR REPLACE PROCEDURE vm_ski.addAdmin
#pUsername NVARCHAR(50),
#pPassword NVARCHAR(50),
#pFornavn NVARCHAR(30),
#pEtternavn NVARCHAR(40),
#pEmail NVARCHAR(40),
#responseMessage NVARCHAR(250)='' OUTPUT
AS
BEGIN
SET NOCOUNT ON
BEGIN TRY
INSERT INTO vm_ski.AdminUser (Username, PasswordHash, Fornavn, Etternavn, Email)
VALUES(#pUsername, HASHBYTES('SHA2_512', #pPassword), #pFornavn, #pEtternavn, #pEmail)
SET #responseMessage='Success'
END TRY
BEGIN CATCH
SET #responseMessage=ERROR_MESSAGE()
END CATCH
END;
-- Admin example
DECLARE #responseMessage NVARCHAR(250)
EXECUTE vm_ski.addAdmin
#pUsername = N'sondre',
#pPassword = N'example'
#pFornavn = N'Sondre'
#pEtternavn = N'Morgendal'
#pEmail = N'sondre.example#gmail.com'
;

This is not a direct answer to the question; this is a security note on the methodology of the question
Do NOT hash passwords in MySQL. The data given to MySQL is plaintext, and easily intercepted by MySQL processing logs as well as possibly numerous other places before being dumped in the database (such as if message packets sent to the database are non-localhost and are non-TLS). ( Why? )
When hashing passwords you want to be doing so as early in the process as possible. This typically means using PHP password_hash and simply dumping only the hashed data in the MySQL.
If you do not use PHP to interact with your SQL then you can use other server methods such as Argon2 or Libsodium.
Also as a side point you should be using the mb4 UTF-8 charset and collations - principly utf8mb4_general_ci ( Why? )

Related

How to build a conditional Procedure to operate (if-then-insert-else-update) on multiple tables using MySQL in phpMyAdmin

I use MySQL to manage a database.
I have 2 tables named IDENTITY and OPTIONS in a database named WIFI.
IDENTITY contains 2 fields: USERNAME and PASSWORD.
OPTIONS contains 3 fields: USERNAME, WIFI_SSID and WIFI_PASSWORD.
And there is a procedure accepting these variables as argument:
arg01_USERNAME
arg02_PASSWORD
arg03_WIFI_SSID
arg04_WIFI_PASSWORD
I want to build a procedure in phpMyAdmin to do this operation:
This procedure should check if the arg01_USERNAME and arg02_PASSWORD match the data in IDENTITY. If data not found, then do nothing. Else search for arg01_USERNAME in table OPTIONS and update WIFI_SSID and WIFI_PASSWORD with arg03_WIFI_SSID and arg04_WIFI_PASSWORD. If arg01_USERNAME not found in OPTIONS, then insert a new record into OPTIONS.
Here is the SQL query to define procedure:
CREATE DEFINER=`WIFI`#`localhost` PROCEDURE `INSERT`(IN `arg01_USERNAME` INT(20) UNSIGNED, IN `arg02_PASSWORD` VARCHAR(32), IN `arg03_WIFI_SSID` VARCHAR(32) CHARSET utf8, IN `arg04_WIFI_PASSWORD` VARCHAR(32) CHARSET utf8)
NO SQL
IF EXISTS (
SELECT COUNT(*)
FROM `WIFI`.`IDENTITY`
WHERE `USERNAME` = arg01_USERNAME AND `PASSWORD` = arg02_PASSWORD)
THEN
INSERT INTO `WIFI`.`OPTIONS` (
`USERNAME`,
`WIFI_SSID`,
`WIFI_PASSWORD`
) VALUES (
arg01_USERNAME,
arg03_WIFI_SSID,
arg04_WIFI_PASSWORD
)
ON DUPLICATE KEY UPDATE
`WIFI_SSID` = arg03_WIFI_SSID,
`WIFI_PASSWORD` = arg04_WIFI_PASSWORD
END IF;
ENGINE=InnoDB DEFAULT CHARSET=utf8
Could you please point me out what is wrong with this code?
When I try to define the procedure using this code, phpMyAdmin tells me there is a syntax error near "END IF" part of the code(error 1064).
Sorry for my poor English.
You need to redefined Delimiter to something else, for eg: $$, so that parser does not trigger query execution when it sees ;
At the end, redefine the Delimiter back to ;.
Try:
DELIMITER $$
CREATE DEFINER=`WIFI`#`localhost` PROCEDURE `INSERT`(IN `arg01_USERNAME` INT(20) UNSIGNED, IN `arg02_PASSWORD` VARCHAR(32), IN `arg03_WIFI_SSID` VARCHAR(32) CHARSET utf8, IN `arg04_WIFI_PASSWORD` VARCHAR(32) CHARSET utf8)
NO SQL
IF EXISTS (
SELECT COUNT(*)
FROM `WIFI`.`IDENTITY`
WHERE `USERNAME` = arg01_USERNAME AND `PASSWORD` = arg02_PASSWORD)
THEN
INSERT INTO `WIFI`.`OPTIONS` (
`USERNAME`,
`WIFI_SSID`,
`WIFI_PASSWORD`
) VALUES (
arg01_USERNAME,
arg03_WIFI_SSID,
arg04_WIFI_PASSWORD
)
ON DUPLICATE KEY UPDATE
`WIFI_SSID` = arg03_WIFI_SSID,
`WIFI_PASSWORD` = arg04_WIFI_PASSWORD;
END IF $$
DELIMITER ;

I am trying to create email data using an MySQL procedure. How can I go about not inserting into my email table if the data already exists?

Most of the posts I found involve using PHP but I am not using PHP in my case. Here is my MySQL procedure
CREATE DEFINER=`root`#`localhost` PROCEDURE `create_email`(in UID_ int(20),
in user_id_ int(20),
in from_email_ VARCHAR(1024),
in subject_email_ TINYTEXT,
in body_email_ LONGTEXT,
out id_ BIGINT(20) unsigned )
BEGIN
set id_=0;
INSERT INTO emails (UID, user_id, from_email, subject_email, body_email)
VALUES
(UID_ ,user_id_, from_email_, subject_email_, body_email_);
set id_ = LAST_INSERT_ID();
END
Currently my procedure does not check if the data in the table exists it only inserts as the data is being received. What is an effective way of making sure incoming email data does not dublicate onto my emails table?
Thank you in advance.

Using stored procedure in MySQL

I have a weather database in MySQL. My database get data from arduino, but sometimes the arduino have some error and send error value in my database. I want to make a stored procedure to reject this error. I want using if then in stored procedure. Example if temperature < 20 then MySQL reject this data. Is it possible? Help me please with the coding
this is my table
CREATE TABLE `cuaca_maritim`.`weather_data` (
`idweather` INT(10) NOT NULL,
`temperature` DECIMAL(4,2) NOT NULL,
`HUMID` DECIMAL(4,2) NOT NULL,
`AIRPRESSURE` DECIMAL(6,2) NOT NULL,
`WIND` DECIMAL(4,2) NOT NULL,
PRIMARY KEY (`idweather`))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_bin;
Perhaps you just want a view:
create view good_weather_data as
select wd.*
from weather_data
where temperature >= 20;
I don't really see why a stored procedure would be necessary. You might want a trigger that rejects invalid data values when they are loaded.
I think you can use the following stored procedure to do your work.
DELIMITER #
CREATE OR REPLACE PROCEDURE add_weather_data (IN temp INT)
proc_main: BEGIN
IF (temp > 20) THEN
INSERT INTO weather_data(temperature) VALUES (temp);
END IF;
END proc_main #
DELIMITER;
Here I have only consider the temp you can do the same for other parameters also

MySQL stored procedure - insert multiple rows

My application is logging the details of every http request in several MySQL tables via a stored procedure which is returning a unique request id to the application.
CALL http_req('ip', 'url', 'method', 'timestamp', #error, #request_id);
Now I also want to log all http request headers into a table, each header in a seperate row:
CREATE TABLE `http_header` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`request_id` INT(10) UNSIGNED NOT NULL,
`name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
`value` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
PRIMARY KEY (`id`))
The problem is that each client has a different number and types of headers. I have not found a way to pass all header details to my stored procedure and then insert them into the above table.
Currently I have to generate and execute a second insert query from my application after the stored procedure call to save the headers:
INSERT INTO http_header (request_id, name, value)
VALUES (20153, 'cache-control', 'max-age=0'),
(20153, 'accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'),
(20153, 'accept-encoding', 'gzip,deflate,sdch');
Is is possible save the second query and insert the headers from inside the stored procedure? Like passing all headers as a single string and parse it inside the stored procedure?
Yes, it is possible. MySQL does support sufficient flow control structures (REPEAT, IF) and string processing (LOCATE(), SUBSTRING()) to allow splitting the header strings in the database. Here is a very simplistic example:
CREATE PROCEDURE http_req(IN ip CHAR(12), IN url VARCHAR(512), IN method CHAR(8), IN ts DATETIME, IN headers TEXT, OUT err INT, OUT request_id INT)
BEGIN
DECLARE loc INT;
DECLARE hloc INT;
DECLARE hdr TEXT DEFAULT NULL;
DECLARE hval TEXT DEFAULT NULL;
DECLARE s TEXT DEFAULT NULL;
START TRANSACTION;
INSERT INTO http_requests VALUES (NULL,INET_ATON(ip), url, method, ts);
SELECT last_insert_id() INTO request_id;
REPEAT
SET loc=LOCATE("\n",headers);
IF (loc = 0) THEN
SET s=headers;
ELSE
SET s=SUBSTRING(headers,1,loc-1);
SET headers=SUBSTRING(headers,loc+1);
END IF;
SET hloc=LOCATE(':',s);
IF (hloc = 0) THEN
SET hdr=s;
SET hval='';
ELSE
SET hdr=SUBSTRING(s,1,hloc-1);
SET hval=SUBSTRING(s,hloc+1);
END IF;
INSERT INTO http_header VALUES (null,request_id,hdr,hval);
UNTIL (loc=0) END REPEAT;
COMMIT;
END
There are some obvious problems with this code; like your headers will be stored incorrectly if they contain linefeed (\n). Also there is no error management (e.g. err return value is not populated correctly; no rollback). Fixing these has been left as an exercise to the reader ;)

MySQL encrypt() with salt accepts random characters after password

I have a table with usernames and encrypted passwords.
The passwords are encrypted by means of MySQL encrypt() together with a salt (the first two characters of the password).
Recently I've noticed that MySQL accepts passwords even if they contain random characters at the end.
Suppose we have this kind of table:
SET NAMES utf8;
SET foreign_key_checks = 0;
SET time_zone = 'SYSTEM';
SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `user` (`id`, `username`, `password`) VALUES
(11, 'ricardomontalban', ENCRYPT(11111111,11));
And now I query for my user:
-- The following shows the appropriate response --
SELECT * FROM user WHERE username = "ricardomontalban" AND password = ENCRYPT(11111111,11);
-- HOWEVER, the following query also shows a result, even with random characters appended!!! --
SELECT * FROM user WHERE username = "ricardomontalban" AND password = ENCRYPT("11111111-55669964s5465sqsfqsdf",11);
-- No problem with prepended random characters though --
SELECT * FROM user WHERE username = "ricardomontalban" AND password = ENCRYPT("smlkfjmlsdkfjslqf-11111111",11);
I've created an SQL Fiddle to show this example in real time:
http://sqlfiddle.com/#!2/898d5/9
What am I doing wrong? Should I even be using this encryption method?
Any suggestions are greatly appreciated.
As per the documentation:
ENCRYPT() ignores all but the first eight characters of str, at least on some systems. This behavior is determined by the implementation of the underlying crypt() system call.
To answer your other questions:
Using the first two (or any) characters from the password as the salt is also wrong. The idea of the salt is to provide some randomness to the encrypted passwords so that users who have the same password will have different hashes.
Use an established encryption library (such as bcrypt) for whatever programming language you are using.