How can I avoid sql injection Azure DocumentDB stored procedures?
Apart from sanitizing the input (whitelisted characters) what's the best practice here?
Take for example the following stored procedure adapted from the MSDN example:
function simple_sp(s1) {
var context = getContext();
var collection = context.getCollection();
var response = context.getResponse();
collection.queryDocuments(collection.getSelfLink(),
'SELECT * FROM Families f where f.id = "' + s1 + '"', {},
function(res){}
);
}
That s1 parameter is a standard example injecting sql into the query. So far I have not found a way to parametrize the query either.
Update:
Happy to say that as of 1/14/15 - DocumentDB does support SQL parameterization. Support has been added across the .NET, Java, Node.js, and Python SDKs, as well as the REST API. Enjoy =)
Here's an example using the .NET SDK:
IQueryable<Book> queryable = client.CreateDocumentQuery<Book>(collectionSelfLink, new SqlQuerySpec {
QueryText = "SELECT * FROM books b WHERE (b.Author.Name = #name)",
Parameters = new SqlParameterCollection() {
new SqlParameter("#name", "Herman Melville")
}
});
Original Answer
DocumentDB does not support SQL parametrization yet... so you will want to sanitize your inputs to avoid unintentional exposure of data on reads (e.g. for multi-tenant applications).
That being said... the DocumentDB SQL injection attack surface area is fairly limited - as DocumentDB SQL only supports read-only queries. In other words, you do not have to worry about unintentional writes/updates/deletes in the context of DocumentDB and SQL Injection.
To answer the question as it applies to the stored procedure JavaScript file:
function simple_sp(s1) {
var context = getContext();
var collection = context.getCollection();
var response = context.getResponse();
var query = { query: "select * from Families f where f.id = #id", parameters: [{ name: "#id", value: id }] };
collection.queryDocuments(collection.getSelfLink(),
query, {},
function(res){}
);
}
Related
I can't find out if it's possible to invoke AQL queries set up on the ArangoDb web UI in Foxx script - rather like stored procedures can be called by services of a RDMS.
So far all examples I've seen show the AQL embedded into the Foxx services JavaScript.
const result = db._query([name of query defined in Db], {
"#arg": arg-value
}).toArray();
I would expect the query defined on the ArangoDb to run and pass argument value from Foxx service. but the _query method seems to only accept a query string.
The queries are stored as properties of the user and as such are available via the users-API:
var _ = require("lodash"); // helper to group the queries
var users = require('#arangodb/users');
var myQueries = _.groupBy(users.document(users.currentUser())['extra']['queries'], 'name');
const result = db._query(myQueries['name of query defined in Db'], ...);
lodash is available per default, no need to install it.
This is not clearly documented anywhere -- I took a look at the network traffic of the query-editor, to find the queries under 'extra/queries' of the user; than I searched for a js user-API and found an article on 'User Managment'. I'd say the lack of documentation is a clear 'caveat emptor' -- it might change without notice; but this should get you going.
Additionally, thinking a bit, I only tested this in arangosh, not a foxx app -- maybe the users module isn't available there. If it works you will probably have to replace the users.currentUser() call with the username as string.
Given the ease this approach lends to breaking your application, I wouldn't recommend to use this (if it works...) outside of R&D and/or prototyping.
Edit: I implemented this to test it:
router.post(
'/getQueries',
/**
* #param {Object} req
* #param {Object} res
*/
function(req, res) {
var _ = require("lodash"); // helper to group the queries
var users = require('#arangodb/users');
var myQueries = _.groupBy(users.document(req.body.user, ['extra']['queries'], 'name'));
res.json({success: (myQueries !== null), queries: myQueries, error: null});
}).summary('Return queries stored for the given user').body(joi.object().keys({
'user': joi.string().required()
}).unknown(true), ['json']);
This works, the queries are objects with of the following form:
[
"value" => """
FOR x IN #params\n
RETURN x
""",
"parameter" => [
"params" => "",
],
"name" => "x_test",
],
so a foxx service can indeed access and execute queries stored for a user, but I still strongly suggest to not do this in production.
I'm trying to get a feel for how fast MongoDB is compared to traditional RDBMSs. To this end, I'm using Java to try and get the result of a traditional SQL join by defining a MongoDB function that will return an object after embedding another object into it:
s_with_user = function(rows){
var result=[]
db.subscriptions.find().limit(rows).forEach( function(s) {
s.user= db.users.find({id: s.user_id});
result.push( s );
});
return result;
}
Then, I use:
DB db = new Mongo("localhost", 27017).getDB("test");
Object result = db.eval("s_with_user(1000)");
Measuring the time taken for the last statement, I'm confident that MongoDB is running the command and evaluating the data I want. However, the result object is always null.
How can I do this in such a way that I can inspect the results?
First of all, Stennie is right about eval() not being the right way to do joins in MongoDB.
However, to try to answer your question, it would work this way:
String f = "function(rows) { ... }";
DB db = new Mongo("localhost", 27017).getDB("test");
Object result = db.eval( f, 1000 );
Also, your "join" function needs a small correction: it should use findOne instead of find:
s.user = db.users.findOne({id: s.user_id});
I'm using OLE and C#.NET to query the schema of a MS Access database. Specifically, I need to find out whether a particular column is an "identity" column or not. For SQL Server, I can use:
select COLUMNPROPERTY(object_id('dbo.tablename'),'columnname','IsIdentity')
... but when I invoke this SQL against Access, I get an OleDbException with the following message:
Undefined function 'COLUMNPROPERTY' in expression.
Searching the archives, it appears there are ways to do this with DAO, but I need to use OLE. Anyone happen to know how I can do this with OLE?
You can get the schema from the connection, for example:
cn.GetOleDbSchemaTable(OleDbSchemaGuid.Indexes,
new Object[] { null, null, null, null, "Table1" });
Is the indexes for Table1. One of the fields returned is PRIMARY_KEY
See http://msdn.microsoft.com/en-us/library/system.data.oledb.oledbschemaguid.columns(v=vs.71)
The same using the GetSchema method.
using(OleDbConnection con = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;" +
"Data Source=C:\temp\db.mdb;" +
"Persist Security Info=False;"))
{
con.Open();
var schema = con.GetSchema("Indexes");
var col = schema.Select("TABLE_NAME = 'YourTableName' AND PRIMARY_KEY = True");
Console.WriteLine(col[0]["COLUMN_NAME"].ToString());
}
I am using MongoDb for my c sharp project instead of mysql, now i want to use query like select * from student Where (name is null or name='XXX') and (sno is null or sno=10), how can i build this query in mongodb.
thanks,
#dinnu.
This should get you started:
var mongoServer = MongoDB.Driver.MongoServer.Create("mongodb://localhost?safe=true");
var mongoDatabase = mongoServer.GetDatabase("test");
var mongoCollection = mongoDatabase.GetCollection<TModel>("Test");
var cursor = mongoCollection.Find(Query.And(
Query.Or(
Query.EQ("Name", "xxx"),
Query.EQ("Name", null)),
Query.Or(
Query.EQ("sno", 10)),
Query.EQ("sno", null)));
Where TModel is the type of the class you want to deserialize from the db. Now you can use cursor to iterate the results of that query, for example:
var someModel = cursor.FirstOrDefault();
Take a look at Fluent Mongo (https://github.com/craiggwilson/fluent-mongo). It adds Linq on top of the official 10gen driver. Thus far I have found using it to be a good experience. It is available via the Nuget or the GitHub.
I want to execute a raw sql using DBContext SqlQuery and then include related entites. I've tried the following but it doesn't load the related entities:
string sql = "Select * from client where id in (select id from activeclient)";
var list = DbContext.Database.SqlQuery<Client>(sql).AsQueryable().Include(c => c.Address).Include(c => c.Contactinfo).ToList();
Any help?
It is not possible. Include works only with ESQL or linq-to-entities because it must be processed during query building to construct correct SQL query. You cannot pass SQL query to this construction mechanism. Moreover your code will result in executing SQL query as is and trying to call Include on resulted enumeration.
You can also use simple linq query to get your result:
var query = from c in context.Clients.Include(c => c.Address).Include(c => c.Contactinfo)
join ac in context.ActiveClients on c.Id equals ac.Id
select c;
This should produce inner join in SQL and thus filter are non-active clients.
Not direct answer, but instead of writing raw sql query you could use something like this
_conext.Clients.Where(c => _conext.ActiveClients.Any(a => a.ClientId == c.Id));