views:

88

answers:

5

Well the question is self-explanatory. One more thing would be, if it is a security risk then please provide an example of what the user could do. In this case the primary key would be something like : "Product ID"

Thanks!

+5  A: 

No more than showing any other piece of data. If you're vulnerable to SQL injection attacks then showing the primary key is probably the least of your concerns.

Think about it this way, if someone can execute arbitrary sql against your db, which is going to cause more harm: delete from users where id = 100 or delete from users where surname = 'smith'?

Dave
thanks a lot of your reponse!
Bilzac
+1  A: 

if it includes readable information for some confidential data element, then yes.

Charles Bretana
thanks a lot of your reponse!
Bilzac
@Bilzak, Sorry for flip answer, couldn't resist... yr question, obviously, has two levels to it... answer at first level is totally based on design of the rest of yr system, answer at second level is obvious... I was trying to humourously speak to that distinction. I obviously failed.
Charles Bretana
+4  A: 

I don't think there is an inherent risk of exposing the primary key field, but I see no advantage to advertising it as such. (I know I may be reading deeper into your question than you intended)

If you have a ProductId that lets your client identify some product, that's fine to display. The security risk is minimal, IMO. I just would not expose the fact that you used ProductId as a primary key - implementation details should be hidden, even while exposing the content.

SethO
thanks a lot of your reponse!
Bilzac
A: 

Not necessarily. But if you ever wind up changing primary key types along the way (or database providers altogether necessitating the change), abstracting your primary keys to your application-level developers is a good idea. What you do is create an interface which abstracts the primary key at that level, but the data layer knows about it via its implementation. Here's an example:

namespace Aesop.DataAccess
{
    // System namespaces
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Xml.Serialization;

    /// <summary>
    /// Represents an object's unique key in order to abstract out the
    /// underlying key generation/maintenance mechanism.
    /// </summary>
    /// <typeparam name="T">The type the key is representing.</typeparam>
    [ServiceContract]
    public interface IModelIdentifier<T> : ISerializable, IXmlSerializable
    {
        /// <summary>
        /// Gets a string representation of the domain the model originated
        /// from.
        /// </summary>
        string Origin
        {
            [OperationContract]
            get;
        }

        /// <summary>
        /// The model instance identifier for the model object that this
        /// <see cref="IModelIdentifier{T}"/> refers to.  Typically, this
        /// is a database key, file name, or some other unique identifier.
        /// </summary>
        /// <typeparam name="TKeyDataType">The expected data type of the
        /// identifier.</typeparam>
        /// <returns>The unique key as the data type specified.</returns>
        [OperationContract]
        TKeyDataType GetKey<TKeyDataType>();

        /// <summary>
        /// Performs an equality check on the two model identifiers and returns
        /// <c>true</c> if they are equal; otherwise <c>false</c> is returned.
        /// All implementations must also override the equal operator.
        /// </summary>
        /// <param name="obj">The identifier to compare against.</param>
        /// <returns>
        ///   <c>true</c> if the identifiers are equal; otherwise
        ///   <c>false</c> is returned.
        /// </returns>
        [OperationContract]
        bool Equals(IModelIdentifier<T> obj);
    }
}

And here's an implementation for a "standard" int primary key:

namespace Aesop.DataAccess
{
    // System namespaces
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.Runtime.Serialization;
    using System.Security.Permissions;
    using System.Xml;
    using System.Xml.Schema;
    using System.Xml.Serialization;

    /// <summary>
    /// Represents an abstraction of the database key for a Model Identifier.
    /// </summary>
    /// <typeparam name="T">The expected owner data type for this identifier.
    /// </typeparam>
    [DebuggerDisplay("Integer Identifier={id}, Origin={Origin}")]
    [Serializable]
    public sealed class IntegerIdentifier<T> : IModelIdentifier<T> where T : class, ISerializable, IXmlSerializable
    {
        /// <summary>
        /// The unique ID.
        /// </summary>
        private int id;

        /// <summary>
        /// Initializes a new instance of the <see cref="IntegerIdentifier&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="id">The unique ID.</param>
        public IntegerIdentifier(int id)
        {
            this.id = id;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="IntegerIdentifier&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="info">The
        /// <see cref="T:System.Runtime.Serialization.SerializationInfo"/> from
        /// which to retrieve the data.</param>
        /// <param name="context">The source (see
        /// <see cref="T:System.Runtime.Serialization.StreamingContext"/>) for
        /// this deserialization.</param>
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        private IntegerIdentifier(
            SerializationInfo info,
            StreamingContext context)
        {
            if (info == null)
            {
                throw new ArgumentNullException("info");
            }

            this.id = info.GetInt32("id");
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="IntegerIdentifier&lt;T&gt;"/> class from being created.
        /// </summary>
        private IntegerIdentifier()
        {
        }

        /// <summary>
        /// Gets a string representation of the domain the model originated
        /// from.
        /// </summary>
        public string Origin
        {
            get
            {
                return this.GetType().Namespace;
            }
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="integerIdentifier1">The first Model Identifier to
        /// compare.</param>
        /// <param name="integerIdentifier2">The second Model Identifier to
        /// compare.</param>
        /// <returns>
        ///   <c>true</c> if the instances are equal; otherwise
        ///   <c>false</c> is returned.
        /// </returns>
        public static bool operator ==(
            IntegerIdentifier<T> integerIdentifier1,
            IntegerIdentifier<T> integerIdentifier2)
        {
            return object.Equals(integerIdentifier1, integerIdentifier2);
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="integerIdentifier1">The first Model Identifier to
        /// compare.</param>
        /// <param name="integerIdentifier2">The second Model Identifier to
        /// compare.</param>
        /// <returns>
        ///   <c>true</c> if the instances are equal; otherwise
        ///   <c>false</c> is returned.
        /// </returns>
        public static bool operator !=(
            IntegerIdentifier<T> integerIdentifier1,
            IntegerIdentifier<T> integerIdentifier2)
        {
            return !object.Equals(integerIdentifier1, integerIdentifier2);
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is
        /// equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with
        /// the current <see cref="T:System.Object"/>.</param>
        /// <returns>true if the specified <see cref="T:System.Object"/> is
        /// equal to the current <see cref="T:System.Object"/>; otherwise,
        /// false.</returns>
        /// <exception cref="T:System.NullReferenceException">The
        /// <paramref name="obj"/> parameter is null.</exception>
        public override bool Equals(object obj)
        {
            return this.Equals(obj as IModelIdentifier<T>);
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public override int GetHashCode()
        {
            return this.id.GetHashCode();
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return this.id.ToString(CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// The model instance identifier for the model object that this
        /// <see cref="IModelIdentifier{T}"/> refers to.  Typically, this is a
        /// database key, file name, or some other unique identifier.
        /// </summary>
        /// <typeparam name="TKeyDataType">The expected data type of the
        /// identifier.</typeparam>
        /// <returns>The unique key as the data type specified</returns>
        public TKeyDataType GetKey<TKeyDataType>()
        {
            return (TKeyDataType)Convert.ChangeType(
               this.id,
               typeof(TKeyDataType),
               CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// Performs an equality check on the two model identifiers and
        /// returns <c>true</c> if they are equal; otherwise <c>false</c>
        /// is returned.  All implementations must also override the equal
        /// operator.
        /// </summary>
        /// <param name="obj">The identifier to compare against.</param>
        /// <returns>
        ///   <c>true</c> if the identifiers are equal; otherwise
        ///   <c>false</c> is returned.
        /// </returns>
        public bool Equals(IModelIdentifier<T> obj)
        {
            if (obj == null)
            {
                return false;
            }

            return obj.GetKey<int>() == this.GetKey<int>();
        }

        /// <summary>
        /// Populates a
        /// <see cref="T:System.Runtime.Serialization.SerializationInfo"/> with
        /// the data needed to serialize the target object.
        /// </summary>
        /// <param name="info">The
        /// <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to
        /// populate with data.</param>
        /// <param name="context">The destination (see
        /// <see cref="T:System.Runtime.Serialization.StreamingContext"/>) for
        /// this serialization.</param>
        /// <exception cref="T:System.Security.SecurityException">The caller
        /// does not have the required permission. </exception>
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        public void GetObjectData(
            SerializationInfo info,
            StreamingContext context)
        {
            if (info == null)
            {
                throw new ArgumentNullException("info");
            }

            info.AddValue("id", this.id);
        }

        /// <summary>
        /// This method is reserved and should not be used. When implementing
        /// the IXmlSerializable interface, you should return null (Nothing in
        /// Visual Basic) from this method, and instead, if specifying a custom
        /// schema is required, apply the
        /// <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/>
        /// to the class.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Xml.Schema.XmlSchema"/> that describes the
        /// XML representation of the object that is produced by the
        /// <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/>
        /// method and consumed by the
        /// <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/>
        /// method.
        /// </returns>
        public XmlSchema GetSchema()
        {
            return null;
        }

        /// <summary>
        /// Generates an object from its XML representation.
        /// </summary>
        /// <param name="reader">The <see cref="T:System.Xml.XmlReader"/>
        /// stream from which the object is deserialized.</param>
        public void ReadXml(XmlReader reader)
        {
            if (reader != null)
            {
                this.id = Convert.ToInt32(
                    reader.GetAttribute("id"),
                    CultureInfo.InvariantCulture);
            }
        }

        /// <summary>
        /// Converts an object into its XML representation.
        /// </summary>
        /// <param name="writer">The <see cref="T:System.Xml.XmlWriter"/>
        /// stream to which the object is serialized.</param>
        public void WriteXml(XmlWriter writer)
        {
            if (writer != null)
            {
                writer.WriteAttributeString(
                    "id",
                    this.id.ToString(CultureInfo.InvariantCulture));
            }
        }

        /// <summary>
        /// Generates an object from its string representation.
        /// </summary>
        /// <param name="value">The value of the model's type.</param>
        /// <returns>A new instance of this class as it's interface containing
        /// the value from the string.</returns>
        internal static IModelIdentifier<T> FromString(string value)
        {
            int id;

            if (int.TryParse(
                value,
                NumberStyles.None,
                CultureInfo.InvariantCulture,
                out id))
            {
                return new IntegerIdentifier<T>(id);
            }

            return null;
        }

        /// <summary>
        /// Generates an object from its XML representation.
        /// </summary>
        /// <param name="reader">The <see cref="T:System.Xml.XmlReader"/>
        /// stream from which the object is deserialized.</param>
        /// <returns>A new instance of this class as it's interface containing
        /// the value from the XmlReader.</returns>
        internal static IModelIdentifier<T> FromXml(XmlReader reader)
        {
            if (reader != null)
            {
                return new IntegerIdentifier<T>(Convert.ToInt32(
                    reader.GetAttribute("id"),
                    CultureInfo.InvariantCulture));
            }

            return null;
        }
    }
}
Jesse C. Slicer
A: 

Obviously that depends on what information the key contains. It's conceivable that it could be sensitive (an account number perhaps). Maybe Product ID is senstitive information in your application but I don't see why the fact that it's a primary key should make it any more or less of a security risk.

dportas