Stored procedure does not have SELECT permission [closed] - sql-server

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 days ago.
Improve this question
If on SQL Server, only the user is given the EXECUTE permission, it is reasonable to say that as long as the query SP is executed, even if the permission is not given, it should be able to execute it. Why does it say that there is no select permission when executing the query SP, such as adding and modifying? , The deleted SP can be executed normally, and the user is not given insert, update, delete permissions
DB: shop_sample
SP: member_search
User: TEST
Database role: db_denydatawriter
Restrictions:
Do not use EXECUTE AS
Do not create another SCHEMA
The user only has the SP execute authority, and has no insert, update, delete, select authority
Specific database shop_sample can execute SP
When I set
The following message will be reported:
Schema description 'dbo', database 'Shop_sample', object 'role.memberdata' does not have SELECT permission
When using a different query SP,
One is select * from table
One is with parameters,
Why do those with parameters say that there is no select permission, but those without parameters can be executed normally?
If I use grant select but it still fails
Grant select on [dbo].[member_search] to [TEST];
GO
Granted or revoked permission SELECT is incompatible with object
Thank you very much for your assistance. Thank you in advance
Can someone tell me how to set user auth in SSMS?

First, you cannot give select permission on a procedure. Instead, you can give select permissions to one specific table (or, well, all of them).
Now to clarify you thoughts about "if you have execute on a procedure, it should run". It usually seems like that, but is actually more complicated. As the excellent article by Erland Sommarskog indicates, this happens only when the procedure owner and the table owner is the same. In many cases, the owner is just [dbo], and it all works. But it might not be so in your case.
To complicate things further, even if the owner of the proc and table are the same, if you use dynamic SQL, this is instantiated as a nameless procedure with no owner, which will fail the comparison and force object-level checks for each table. In that case, you will have to have the procedure signed.

Related

grant a user to execute only one stored procedure but can't run other queries

Is it possible to grant a user execution on a stored procedure but prevent him of running other queries even if he typed the exact same stored procedure?
Basically what I'm trying to achieve here is to prevent a user to see all rows in a view(select all from View1), but he can select only one row with 'where' condition by a stored procedure.
Yes, it is possible, simply take away all the permissions of that user and grant the user only execute permission on a single procedure.
GRANT EXECUTE ON dbo.ProcedureName TO [UserName];
or
GRANT EXECUTE ON OBJECT::dbo.ProcedureName TO [UserName];
Why not create a view for that user that is limited to only the data that particular user has access to? No need to have a stored procedure for simply accessing a row of data.
By using a limited view, the user can choose to incorporate that view record into a query as a JOIN, or write their own stored procedure/function as they see fit. A view would be a more flexible way to do what you are attempting.

Where is result of OBJECT_NAME(##PROCID) obtained from? (typo corrected)

I have a stored procedure that has EXECUTE AS another user that has very restricted access. I cannot get the results from OBJECT_NAME(##PROCID) when I run that stored procedure. ##PROCID does have a value, so it's the lookup that is failing.
I think it's a permissions issue, so can someone tell me where the name of the stored procedure is obtained from? Maybe I can fix my issue by granting some SELECT permissions to the EXECUTE AS user.
If anyone has any other ideas, LMK. I'm hardcoding the stored procedure name for now.
From the documentation for OBJECT_ID:
A user can only view the metadata of securables that the user owns or on which the user has been granted permission. This means that metadata-emitting, built-in functions such as OBJECT_ID may return NULL if the user does not have any permission on the object.
Also further reading will also tell you that you need to grant the user any permission on the object (i.e. SELECT, EXECUTE etc.)

mssql Stored Procedure permissions problem

I am testing the permissions in mssql and run into a problem. I've made a 'Countries' table and a 'spCountries' Stored procedure. Now I've made a user 'silverlight' and gave it no rights to the Countries table. The user can execute the stored procedure.
Now when I do a Select it fails like it should, but in a exec spCountries, al the data is visible. How can I check for the permissions in the stored procedure?
Is this also possible if the stored procedure does EXEC "SELECT * FROM Countries" instead of just SELECT FROM ...?
Maybe it's also better just to return an empty recordset instead of an error...
Does somebody have an idea?
SELECT has_perms_by_name('dbo.Countries', 'OBJECT', 'SELECT')
That's due to ownership chaining. Basically, if the same principal (e.g. dbo) owns an SP and a table used int it, permissions for the table are not checked.
Actually, this makes sense. For instance, it allows you to give a user acces to some data, but only in specifiŅ ways coded in the SPs.
If you use dynamic SQL, the permissions are calculated every time. Since SQL2005 you can use EXECUTE AS clause to specify execution context. For example, EXECUTE AS OWNER makes dynamic SQL in the SP execute in SP owner's context, giving similar effect to ownership chaining with static SQL.
That is how permissions work in SQL Server.
So you can give permissions on stored procedures without having to give permissions to the underlying objects. This allows you to exercise control over exactly what updates etc. people can make.
Don't give the user silverlight permissions to execute the stored procedure if you don't want them to execute it!
Edit: Although having read the question again it sounds like maybe this is the kind of thing you need?

If my database user is read only, why do I need to worry about sql injection?

Can they (malicious users) describe tables and get vital information? What about if I lock down the user to specific tables? I'm not saying I want sql injection, but I wonder about old code we have that is susceptible but the db user is locked down. Thank you.
EDIT: I understand what you are saying but if I have no response.write for the other data, how can they see it. The bringing to crawl and dos make sense, so do the others but how would they actually see the data?
Someone could inject SQL to cause an authorization check to return the equivalent of true instead of false to get access to things that should be off-limits.
Or they could inject a join of a catalog table to itself 20 or 30 times to bring database performance to a crawl.
Or they could call a stored procedure that runs as a different database user that does modify data.
'); SELECT * FROM Users
Yes, you should lock them down to only the data (tables/views) they should actually be able to see, especially if it's publicly facing.
Only if you don't mind arbitrary users reading the entire database. For example, here's a simple, injectable login sequence:
select * from UserTable where userID = 'txtUserName.Text' and password = 'txtPassword.Text'
if(RowCount > 0) {
// Logged in
}
I just have to log in with any username and password ' or 1 = 1 to log in as that user.
Be very careful. I am assuming that you have removed drop table, alter table, create table, and truncate table, right?
Basically, with good SQL Injection, you should be able to change anything that is dependent on the database. This could be authorization, permissions, access to external systems, ...
Do you ever write data to disk that was retrieved from the database? In that case, they could upload an executable like perl and a perl file and then execute them to gain better access to your box.
You can also determine what the data is by leveraging a situation where a specific return value is expected. I.e. if the SQL returns true, execution continues, if not, execution stops. Then, you can use a binary search in your SQL. select count(*) where user_password > 'H'; If the count is > 0 it continues. Now, you can find the exact plain text password without requiring it to ever be printed on the screen.
Also, if your application is not hardened against SQL errors, there might be a case where they can inject an error in the SQL or in the SQL of the result and have the result display on the screen during the error handler. The first SQL statement collects a nice list of usernames and passwords. The second statement tries to leverage them in a SQL condition for which they are not appropriate. If the SQL statement is displayed in this error condition, ...
Jacob
I read this question and answers because I was in the process of creating a SQL tutorial website with a readonly user that would allow end users to run any SQL.
Obviously this is risky and I made several mistakes. Here is what I learnt in the first 24 hours (yes most of this is covered by other answers but this information is more actionable).
Do not allow access to your user table or system tables:
Postgres:
REVOKE ALL ON SCHEMA PG_CATALOG, PUBLIC, INFORMATION_SCHEMA FROM PUBLIC
Ensure your readonly user only has access to the tables you need in
the schema you want:
Postgres:
GRANT USAGE ON SCHEMA X TO READ_ONLY_USER;
GRANT SELECT ON ALL TABLES IN SCHEMA X TO READ_ONLY_USER
Configure your database to drop long running queries
Postgres:
Set statement_timeout in the PG config file
/etc/postgresql/(version)/main/postgresql.conf
Consider putting the sensitive information inside its own Schema
Postgres:
GRANT USAGE ON SCHEMA MY_SCHEMA TO READ_ONLY_USER;
GRANT SELECT ON ALL TABLES IN SCHEMA MY_SCHEMA TO READ_ONLY_USER;
ALTER USER READ_ONLY_USER SET SEARCH_PATH TO MY_SCHEMA;
Take care to lock down any stored procedures and ensure they can not be run by the read only user
Edit: Note by completely removing access to system tables you no longer allow the user to make calls like cast(). So you may want to run this again to allow access:
GRANT USAGE ON SCHEMA PG_CATALOG to READ_ONLY_USER;
Yes, continue to worry about SQL injection. Malicious SQL statements are not just about writes.
Imagine as well if there were Linked Servers or the query was written to access cross-db resources. i.e.
SELECT * from someServer.somePayrollDB.dbo.EmployeeSalary;
There was an Oracle bug that allowed you to crash the instance by calling a public (but undocumented) method with bad parameters.

How can I set a username for a Postgresql audit trigger?

I am using a trigger in PostgreSQL 8.2 to audit changes to a table:
CREATE OR REPLACE FUNCTION update_issue_history() RETURNS trigger as $trig$
BEGIN
INSERT INTO issue_history (username, issueid)
VALUES ('fixed-username', OLD.issueid);
RETURN NULL;
END;
$trig$ LANGUAGE plpgsql;
CREATE TRIGGER update_issue_history_trigger
AFTER UPDATE ON issue
FOR EACH ROW EXECUTE PROCEDURE update_issue_history();
What I want to do is have some way to provide the value of fixed-username at the time that I execute the update. Is this possible? If so, how do I accomplish it?
Try something like this:
CREATE OR REPLACE FUNCTION update_issue_history()
RETURNS trigger as $trig$
DECLARE
arg_username varchar;
BEGIN
arg_username := TG_ARGV[0];
INSERT INTO issue_history (username, issueid)
VALUES (arg_username, OLD.issueid);
RETURN NULL;
END;
$trig$ LANGUAGE plpgsql;
CREATE TRIGGER update_issue_history_trigger
AFTER UPDATE ON issue
FOR EACH ROW EXECUTE PROCEDURE update_issue_history('my username value');
I don't see a way to do this other than to create temp tables and use EXECUTE in your trigger. This will have performance consequences though. A better option might be to tie into another table somewhere and log in who logs in/out by session id and back-end PID, and reference that?
Note you don't have any other way of getting the information into the update statement. Keep in mind that the trigger can only see what is available in the API or in the database. If you want a trigger to work transparently, you can't expect to pass information to it at runtime that it would not have access to otherwise.
The basic question you have to ask is "How does the db know what to put there?" Once you decide on a method there the answer should be straight-forward but there are no free lunches.
Update
In the past when I have had to do something like this when the login to the db is with an application role, the way I have done it is to create a temporary table and then access that table from the stored procedures. Currently stored procedures can handle temporary tables in this way but in the past we had to use EXECUTE.
There are two huge limitations with this approach. The first is that it creates a lot of tables and this leads eventually to the possibility of oid wraparound.
These days I much prefer to have the logins to the db being user logins. This makes this far easier to manage and you can just access via the value SESSION_USER (a newbie mistake is to use CURRENT_USER which shows you the current security context rather than the login of the user.
Neither of these approaches work well with connection pooling. In the first case you can't do connection pooling because your temporary tables will get misinterpreted or clobbered. In the second, you can't do it because the login roles are different.

Resources